Запрос URL-адреса Swift / iOS к конечной точке API Node.js - PullRequest
0 голосов
/ 27 апреля 2019

У меня есть стандартный код в 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()


    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...