URLSessionDataTask игнорирует свойство httpMethod URLRequest - PullRequest
0 голосов
/ 15 февраля 2019

У меня странная проблема, из-за которой я не могу выполнить простой запрос POST к службе REST, которой я не управляю на основе GraphQL.

Проблема в том, что независимо от того, что я установил в httpMethod свойство класса URLRequest, вместо него всегда используется GET.

Я провел несколько тестов, чтобы устранить некоторые проблемы.Например, я настроил заголовок в Запросе и могу убедиться, что заголовок отправляется на сервер (проверено с помощью Charles Proxy).

Этот код можно вставить и запустить на игровой площадке:

import PlaygroundSupport
import Foundation
PlaygroundPage.current.needsIndefiniteExecution = true

let url = URL(string: "http://graphql.anilist.co/")!
let internalSession = URLSession(configuration: .default)
var request = URLRequest(url: url)
request.httpMethod = "POST"
let headers = ["content-type": "application/json"]
request.allHTTPHeaderFields = headers
request.httpBody =
"""
{"query":"query (\n\t$season: MediaSeason,\n\t$year: Int,\n\t$format: MediaFormat,\n\t$excludeFormat: MediaFormat,\n\t$status: MediaStatus,\n\t$minEpisodes: Int,\n\t$page: Int,\n){\n\tPage(page: $page) {\n\t\tpageInfo {\n\t\t\thasNextPage\n\t\t\ttotal\n\t\t}\n\t\tmedia(\n\t\t\tseason: $season\n\t\t\tseasonYear: $year\n\t\t\tformat: $format,\n\t\t\tformat_not: $excludeFormat,\n\t\t\tstatus: $status,\n\t\t\tepisodes_greater: $minEpisodes,\n\t\t\tisAdult: false,\n\t\t\ttype: ANIME,\n\t\t\tsort: TITLE_ROMAJI,\n\t\t) {\n\t\t\t\nid\nidMal\ntitle {\n\tromaji\n\tnative\n\tenglish\n}\nstartDate {\n\tyear\n\tmonth\n\tday\n}\nendDate {\n\tyear\n\tmonth\n\tday\n}\nstatus\nseason\nformat\ngenres\nsynonyms\nduration\npopularity\nepisodes\nsource(version: 2)\ncountryOfOrigin\nhashtag\naverageScore\nsiteUrl\ndescription\nbannerImage\ncoverImage {\n\textraLarge\n\tcolor\n}\ntrailer {\n\tid\n\tsite\n\tthumbnail\n}\nexternalLinks {\n\tsite\n\turl\n}\nrankings {\n\trank\n\ttype\n\tseason\n\tallTime\n}\nstudios(isMain: true) {\n\tnodes {\n\t\tid\n\t\tname\n\t\tsiteUrl\n\t}\n}\nrelations {\n\tedges {\n\t\trelationType(version: 2)\n\t\tnode {\n\t\t\tid\n\t\t\ttitle {\n\t\t\t\tromaji\n\t\t\t\tnative\n\t\t\t\tenglish\n\t\t\t}\n\t\t\tsiteUrl\n\t\t}\n\t}\n}\n\nairingSchedule(\n\tnotYetAired: true\n\tperPage: 2\n) {\n\tnodes {\n\t\tepisode\n\t\tairingAt\n\t}\n}\n\n\t\t}\n\t}\n}","variables":{"season": WINTER,"year": 2019,"page": 1, "perPage": 100}}
""".data(using: .utf8)
print("THE REQUEST \(String(describing: request.httpMethod))")
let task = internalSession.dataTask(with: request, completionHandler: { (data, response, error) in
    if let e = error {
        print("ERROR: \(e)")
    } else if let response = response as? HTTPURLResponse {
        print("THE RESPONSE: \(response)")
        let json = try! JSONSerialization.jsonObject(with: data!, options: [])
        print(json)
    }
})
task.resume()

(Пожалуйста, игнорируйте все дополнительные параметры принудительного развертывания и принудительное try!, это код теста).

Ожидаемый результат

Iожидаем, что веб-служба выдаст JSON, аналогичный этому (упрощенно):

{
    "data": {
        "Page": {
            "pageInfo": {
                "hasNextPage": true,
                "total": 81
            },
            "media": [
                {
                    "id": 102882,
                    "idMal": 37956,
                    "title": {
                        "romaji": "3D Kanojo: Real Girl 2",
                        "native": "3D彼女 リアルガール 2",
                        "english": "Real Girl 2"
                    },
                    "startDate": {
                        "year": 2019,
                        "month": 1,
                        "day": 9
                    },
                    "endDate": {
                        "year": null,
                        "month": null,
                        "day": null
                    },
                    "status": "RELEASING",
                    "season": "WINTER",
                    "format": "TV",
                    "genres": [
                        "Romance",
                        "Slice of Life",
                        "Comedy"
                    ],
                    "synonyms": [],
                    "duration": 23,
                    "popularity": 3298,
                    "episodes": 12,
                    "source": "MANGA",
                    "countryOfOrigin": "JP",
                    "hashtag": "#3D彼女リアルガール #3D彼女",
                    "averageScore": 61,
                    "siteUrl": "https://anilist.co/anime/102882",
                    "description": "The second season of <i>3D Kanojo</i>.",
                    "bannerImage": null,
                    "coverImage": {
                        "extraLarge": "https://s4.anilist.co/file/anilistcdn/media/anime/cover/large/nx102882-lKp3ExWNzoE6.jpg",
                        "color": "#e4bb93"
                    },
                    "trailer": {
                        "id": "x6yokzp",
                        "site": "dailymotion",
                        "thumbnail": "https://www.dailymotion.com/thumbnail/video/x6yokzp"
                    },
                    "externalLinks": [
                        {
                            "site": "Official Site",
                            "url": "http://www.3dkanojo-anime.com/"
                        },
                        {
                            "site": "Twitter",
                            "url": "https://twitter.com/3Dkanojo_anime"
                        }
                    ],
                    "rankings": [
                        {
                            "rank": 16,
                            "type": "RATED",
                            "season": null,
                            "allTime": false
                        },
                        {
                            "rank": 19,
                            "type": "POPULAR",
                            "season": null,
                            "allTime": false
                        },
                        {
                            "rank": 16,
                            "type": "RATED",
                            "season": "WINTER",
                            "allTime": false
                        },
                        {
                            "rank": 15,
                            "type": "POPULAR",
                            "season": "WINTER",
                            "allTime": false
                        }
                    ],
                    "studios": {
                        "nodes": [
                            {
                                "id": 346,
                                "name": "Hoods Entertainment",
                                "siteUrl": "https://anilist.co/studio/346"
                            }
                        ]
                    },
                    "relations": {
                        "edges": [
                            {
                                "relationType": "PREQUEL",
                                "node": {
                                    "id": 100526,
                                    "title": {
                                        "romaji": "3D Kanojo: Real Girl",
                                        "native": "3D彼女 リアルガール",
                                        "english": "Real Girl"
                                    },
                                    "siteUrl": "https://anilist.co/anime/100526"
                                }
                            },
                            {
                                "relationType": "SOURCE",
                                "node": {
                                    "id": 80767,
                                    "title": {
                                        "romaji": "3D Kanojo: Real Girl",
                                        "native": "3D彼女 〈リアルガール〉",
                                        "english": "Real Girl"
                                    },
                                    "siteUrl": "https://anilist.co/manga/80767"
                                }
                            }
                        ]
                    },
                    "airingSchedule": {
                        "nodes": [
                            {
                                "episode": 7,
                                "airingAt": 1550595540
                            },
                            {
                                "episode": 8,
                                "airingAt": 1551200340
                            }
                        ]
                    }
                }
            ]
        }
    }
}

Полученный результат

Вместо этого я получаю следующее:

{
    "data": null,
    "errors": [
        {
            "message": "Not Found.",
            "hint": "Use POST request to access graphql subdomain.",
            "status": 404
        }
    ]
}

Служба жалуется, что запрос является запросом GET и должен быть POST, и я прямо говорю URLRequest использовать вместо него POST.Если вы посмотрите на запрос в Charles или другом прокси-сервере, вы действительно увидите, что запрос выполняется как запрос GET, а свойство httpBody отбрасывается.Если вы отредактируете заголовки и добавите еще один заголовок, например, так:

let headers = ["content-type": "application/json", "foo": "bar"]

В своем прокси вы увидите, что заголовок отправляется правильно.

Единственный вывод, который я могу получить, заключается в том, чтос URLSessionDataTask существует внутренняя проблема, которая заставляет выполнять только запросы GET.Я попытался изменить его на задачу загрузки, но та же проблема происходит.Так что должна быть проблема с моим кодом, но я не могу его найти.

РЕДАКТИРОВАТЬ:

Для запроса, это запрос, который использует Почтальон.Я экспортировал запрос в CURL, чтобы его можно было легко импортировать.

curl -X POST \
  https://graphql.anilist.co/ \
  -H 'Content-Type: application/json' \
  -H 'Postman-Token: 49d7e55e-35c2-4a3c-82f0-4eccb1250fc0' \
  -H 'cache-control: no-cache' \
  -d '{"query":"query (\n\t$season: MediaSeason,\n\t$year: Int,\n\t$format: MediaFormat,\n\t$excludeFormat: MediaFormat,\n\t$status: MediaStatus,\n\t$minEpisodes: Int,\n\t$page: Int,\n){\n\tPage(page: $page) {\n\t\tpageInfo {\n\t\t\thasNextPage\n\t\t\ttotal\n\t\t}\n\t\tmedia(\n\t\t\tseason: $season\n\t\t\tseasonYear: $year\n\t\t\tformat: $format,\n\t\t\tformat_not: $excludeFormat,\n\t\t\tstatus: $status,\n\t\t\tepisodes_greater: $minEpisodes,\n\t\t\tisAdult: false,\n\t\t\ttype: ANIME,\n\t\t\tsort: TITLE_ROMAJI,\n\t\t) {\n\t\t\t\nid\nidMal\ntitle {\n\tromaji\n\tnative\n\tenglish\n}\nstartDate {\n\tyear\n\tmonth\n\tday\n}\nendDate {\n\tyear\n\tmonth\n\tday\n}\nstatus\nseason\nformat\ngenres\nsynonyms\nduration\npopularity\nepisodes\nsource(version: 2)\ncountryOfOrigin\nhashtag\naverageScore\nsiteUrl\ndescription\nbannerImage\ncoverImage {\n\textraLarge\n\tcolor\n}\ntrailer {\n\tid\n\tsite\n\tthumbnail\n}\nexternalLinks {\n\tsite\n\turl\n}\nrankings {\n\trank\n\ttype\n\tseason\n\tallTime\n}\nstudios(isMain: true) {\n\tnodes {\n\t\tid\n\t\tname\n\t\tsiteUrl\n\t}\n}\nrelations {\n\tedges {\n\t\trelationType(version: 2)\n\t\tnode {\n\t\t\tid\n\t\t\ttitle {\n\t\t\t\tromaji\n\t\t\t\tnative\n\t\t\t\tenglish\n\t\t\t}\n\t\t\tsiteUrl\n\t\t}\n\t}\n}\n\nairingSchedule(\n\tnotYetAired: true\n\tperPage: 2\n) {\n\tnodes {\n\t\tepisode\n\t\tairingAt\n\t}\n}\n\n\t\t}\n\t}\n}","variables":{"year":2019,"season":"WINTER","page":1, "limit": 12}}'

1 Ответ

0 голосов
/ 15 февраля 2019

Единственное отличие, которое я вижу здесь, это http:// на вашей детской площадке и https:// на вашем почтальоне.

Так что просто замените http:// на https:// в вашем Playground.

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