Podczas budowania GET
żądania nie ma treści, ale raczej wszystko trafia do adresu URL. Aby zbudować adres URL (i odpowiednio zmienić wartość procentową zmiany znaczenia), możesz również użyć URLComponents
.
var url = URLComponents(string: "https://www.google.com/search/")!
url.queryItems = [
URLQueryItem(name: "q", value: "War & Peace")
]
Jedyna sztuczka polega na tym, że większość usług internetowych wymaga +
znaku procentowego ucieczki (ponieważ będą interpretować to jako znak spacji zgodnie ze application/x-www-form-urlencoded
specyfikacją ). Ale URLComponents
procent nie ucieknie od tego. Firma Apple twierdzi, że +
jest to prawidłowy znak w zapytaniu i dlatego nie należy go zmieniać. Technicznie są poprawne, że jest to dozwolone w zapytaniu o identyfikator URI, ale ma to specjalne znaczenie w application/x-www-form-urlencoded
żądaniach i naprawdę nie powinno być przekazywane bez zmiany znaczenia.
Apple przyznaje, że musimy procentować unikaniem +
znaków, ale radzi, abyśmy robili to ręcznie:
var url = URLComponents(string: "https://www.wolframalpha.com/input/")!
url.queryItems = [
URLQueryItem(name: "i", value: "1+2")
]
url.percentEncodedQuery = url.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
Jest to nieeleganckie obejście, ale działa i Apple radzi, jeśli twoje zapytania mogą zawierać +
znak, a masz serwer, który interpretuje je jako spacje.
Łącząc to ze swoją sendRequest
rutyną, otrzymujesz coś takiego:
func sendRequest(_ url: String, parameters: [String: String], completion: @escaping ([String: Any]?, Error?) -> Void) {
var components = URLComponents(string: url)!
components.queryItems = parameters.map { (key, value) in
URLQueryItem(name: key, value: value)
}
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let request = URLRequest(url: components.url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data,
let response = response as? HTTPURLResponse,
(200 ..< 300) ~= response.statusCode,
error == nil else {
completion(nil, error)
return
}
let responseObject = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
completion(responseObject, nil)
}
task.resume()
}
I nazwałbyś to tak:
sendRequest("someurl", parameters: ["foo": "bar"]) { responseObject, error in
guard let responseObject = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
}
Osobiście użyłbym JSONDecoder
teraz i zwróciłbym struct
raczej niestandardowy niż słownik, ale to nie jest tutaj naprawdę istotne. Mamy nadzieję, że ilustruje to podstawową koncepcję kodowania procentowego parametrów w adresie URL żądania GET.
Zobacz poprzednią wersję tej odpowiedzi dla wersji Swift 2 i ręcznych wersji ze ucieczką procentową.
extension string
robi z wartościami? Kiedy miałbymHttpBody
wtedy użyć ?