У меня есть стандартный код в Swift, как показано ниже:
private func testFormUrlEncodedRequest() {
let headers = [
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/json"
]
let postData = NSMutableData(data: "user_id=5874ae8ae9a98c2d6cef1da8".data(using: String.Encoding.utf8)!)
postData.append("&offset=0".data(using: String.Encoding.utf8)!)
postData.append("&limit=20".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "http://www.example.com/endpoint")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
ViewController.log(request: request as! URLRequest)
print((request as URLRequest).curlString)
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
ViewController.log(data: data, response: response as? HTTPURLResponse, error: error)
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
}
Но проблема в том, что он зависает, а затем запрашивает время ожидания с ошибкой.REST API написан на Node.js и получает ошибку в модуле body-parser, например, запрос прерван.
Я могу успешно выполнить тот же запрос с помощью POSTMAN или curl (из терминала), и я получаю правильный ответ.
Код на сервере, к которому у меня нет доступа, также выглядит довольно стандартным и использовался в предыдущих проектах, где он тестировался на корректную работу с приложениями для iOS.
Я понятия не имею, почему этот запрос работает с POSTMAN и не работает с URLSession в Swift.
Любая помощь будет полезной.
Вот сообщение об ошибке, выведенное на консоль, которое я получаю:
Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x6000013196e0
{Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}},
NSErrorFailingURLStringKey=http://example.com/api/endpoint, NSErrorFailingURLKey=http://example.com/api/endpoint,
_kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.})
Этот запрос выдает ошибку в следующих случаях: 1. Параметры, закодированные в форме URL в теле HTTP-запроса 2. Необработанное приложение/ json params в теле HTTP-запроса 3. Он работает, если параметры передаются в параметрах запроса 4. Сбой при ошибке прерванного запроса на стороне сервера (модуль body-parser) 5. node.js использует стандартный app.use ()
// support parsing of application/json type post data
app.use(bodyParser.json());
//support parsing of application/x-www-form-urlencoded post data
app.use(bodyParser.urlencoded({ extended: true }));
Используется http без SSL, но в Info.plist есть App Transport Security> Разрешить произвольную загрузку, установленное в YES и т. Д.
ОБНОВЛЕНИЕ: это ошибка на стороне сервера
BadRequestError: request aborted
at IncomingMessage.onAborted (/Users/michzio/Click5Interactive/Reusable Parts/NetworkApi/node_modules/raw-body/index.js:231:10)
at emitNone (events.js:86:13)
at IncomingMessage.emit (events.js:188:7)
at abortIncoming (_http_server.js:381:9)
at socketOnClose (_http_server.js:375:3)
at emitOne (events.js:101:20)
at Socket.emit (events.js:191:7)
at TCP.Socket._destroy.cb._handle.close [as _onclose] (net.js:510:12)
Тестовый код Node.js:
const express = require('express');
const port = 9001;
const app = express();
const bodyParser = require('body-parser');
var todos = [{id:1, title:'buy the milk'}, {id:2, title:'rent a car'}, {id:3, title:'feed the cat'}];
var count = todos.length;
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json());
app.get('/test', (request, response) => {
console.log("-----")
console.log(request.params);
console.log(request.body);
console.log(request.query);
console.log("-----")
response.status(200).json( todos );
});
app.listen(port);
Кажется, что параметры запроса GET + работают, а параметры тела POST + (url-from-encoded или application / json) также работают правильно.
Так что это не работает для GET-параметров тела, закодированных в виде url-формы, и для GET-приложения params / json.Это какое-то ограничение URLSession / URLRequest в Swift.POSTMAN может передавать параметры в теле с помощью GET, а сервер получает их в request.body!
ОБНОВЛЕНИЕ 2!
Да, похоже, что в Android / Kotlin с OkHttpClient нет даже возможности определить тело запроса с помощью метода GET.И есть также эта ошибка.Возможно, это работает только с POSTMAN и curl, и не должно использоваться в реальном сценарии приложения для объединения параметров GET и body.
public fun makeNetworkRequest(v: View) {
object : Thread() {
override fun run() {
val client = OkHttpClient()
val mediaType = MediaType.parse("application/json")
val body = RequestBody.create(mediaType, "{ \"test\" : \"nowy\", \"test2\" : \"lol\" }")
/*
val request = Request.Builder()
.url("http://10.0.2.2:9001/test")
.get()
.addHeader("Content-Type", "application/json")
.build()
*/
val mySearchUrl = HttpUrl.Builder()
.scheme("http")
.host("10.0.2.2")
.port(9001)
.addPathSegment("test")
.addQueryParameter("q", "polar bears")
.build()
val request = Request.Builder()
.url(mySearchUrl)
.addHeader("Accept", "application/json")
.method("GET", body)
.build()
val response = client.newCall(request).execute()
Log.d("RESPONSE", response.toString())
}
}.start()
}