매개 변수가있는 신속한 GET 요청


81

나는 신속하게 매우 새롭기 때문에 아마도 내 코드에 많은 결함이있을 것이지만 내가 달성하려는 것은 GET매개 변수를 사용하여 로컬 호스트 서버에 요청을 보내는 것 입니다. 내 함수가 두 개의 매개 변수를 사용하면 더 많은 것을 달성하려고합니다 baseURL:string,params:NSDictionary. 이 두 가지를 실제 URLRequest에 결합하는 방법을 모르겠습니까? 여기 내가 지금까지 시도한 것입니다

    func sendRequest(url:String,params:NSDictionary){
       let urls: NSURL! = NSURL(string:url)
       var request = NSMutableURLRequest(URL:urls)
       request.HTTPMethod = "GET"
       var data:NSData! =  NSKeyedArchiver.archivedDataWithRootObject(params)
       request.HTTPBody = data
       println(request)
       var session = NSURLSession.sharedSession()
       var task = session.dataTaskWithRequest(request, completionHandler:loadedData)
       task.resume()

    }

}

func loadedData(data:NSData!,response:NSURLResponse!,err:NSError!){
    if(err != nil){
        println(err?.description)
    }else{
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        println(jsonResult)

    }

}

답변:


160

GET요청을 작성할 때 요청에 본문이 없지만 모든 것이 URL에 있습니다. URL을 작성하고 적절하게 이스케이프 처리하려면을 사용할 수도 있습니다 URLComponents.

var url = URLComponents(string: "https://www.google.com/search/")!

url.queryItems = [
    URLQueryItem(name: "q", value: "War & Peace")
]

유일한 트릭은 대부분의 웹 서비스가 +문자 퍼센트 이스케이프 가 필요하다는 것입니다 (왜냐하면 application/x-www-form-urlencoded사양 에 따라 공백 문자로 해석되기 때문입니다 ). 그러나 URLComponents퍼센트가 그것을 벗어나지는 않을 것입니다. Apple +은 쿼리에서 유효한 문자이므로 이스케이프해서는 안된다고 주장합니다. 기술적으로는 정확하고 URI 쿼리에서 허용되지만 application/x-www-form-urlencoded요청 에는 특별한 의미 가 있으며 실제로 이스케이프되지 않은 상태로 전달되어서는 안됩니다.

Apple은 +문자 를 퍼센트 이스케이프해야 함을 인정 하지만 수동으로 수행 할 것을 권장합니다.

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")

이것은 비정상적인 해결 방법이지만 작동하며 쿼리에 +문자 가 포함될 수 있고 이를 공백으로 해석하는 서버가있는 경우 Apple이 권장하는 것 입니다.

그래서 그것을 sendRequest일상 과 결합 하면 다음과 같은 결과를 얻게됩니다.

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,                            // is there data
            let response = response as? HTTPURLResponse,  // is there HTTP response
            (200 ..< 300) ~= response.statusCode,         // is statusCode 2XX
            error == nil else {                           // was there no error, otherwise ...
                completion(nil, error)
                return
        }

        let responseObject = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any]
        completion(responseObject, nil)
    }
    task.resume()
}

그리고 당신은 그것을 다음과 같이 부를 것입니다.

sendRequest("someurl", parameters: ["foo": "bar"]) { responseObject, error in
    guard let responseObject = responseObject, error == nil else {
        print(error ?? "Unknown error")
        return
    }

    // use `responseObject` here
}

개인적으로 나는 JSONDecoder 요즘struct 하고 사전이 아닌 사용자 정의를 반환 하지만 여기서는 실제로 관련이 없습니다. 바라건대 이것은 매개 변수를 GET 요청의 URL로 퍼센트 인코딩하는 방법에 대한 기본 아이디어를 보여줍니다.


Swift 2 및 수동 이스케이프 변환에 대한 이 답변의 이전 개정판을 참조하십시오 .


환상적인 답변에 감사드립니다. 나는 단지 하나의 질문이 있습니다. 나는 extension string가치 에 대해 무엇을하고 있는지에 대해 여전히 약간 혼란 스럽 습니까? 또한 언제 사용해야 HttpBody합니까?
MrSSS16

문자열 확장자는 RFC 3986에 따라 값을 이스케이프하는 비율입니다. URL에서 특별한 의미를 갖는 특정 문자가 있습니다 (예 : &하나의 매개 변수를 다음 매개 변수와 분리하므로 &값 이 발생하면 이스케이프되지 않은 상태로 놓을 수 없음). 에 관해서 는 요청에 사용 HTTPBody해서는 안됩니다GET . 에서 사용 POST되지만 GET.
Rob

이것은 매우 간단 해 보입니다. 대신 github.com/xyyc/SwiftSocket 과 같은 것을 사용하면 어떤 이점 이 있습니까? 이 모든 것이 처음이라 죄송합니다.
jigzat

소켓 라이브러리이고 HTTP이기 때문에 올바른 비교가 아닐 수 있습니다. Closer는 Alamofire비슷 하지만 (a) 더 유연합니다 (JSON 요청, x-www-form-urlencoded 요청, 멀티 파트 등을 처리 할 수 ​​있음). (b)보다 기능적 (예 : 인증 문제 처리) (c) HTTP 프로그래밍의 잡초에서 벗어날 수 있습니다. 위의 대답 NSMutableURLRequest은 OP가 제안하는 것보다 더 많은 것이 있음을 지적하면서 자신만의 위험을 경고하기위한 것 입니다.
Rob

이것은 아름다운 해결책입니다. 감사합니다 @Rob. Btw 이와 같은 매개 변수를 제공하는 데 차이가 NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: nil)있습니까? parameters사전의 배열 인[String: String]
ISURU

94

NSURLComponents를 사용하여 다음과 같이 NSURL을 빌드하십시오.

var urlComponents = NSURLComponents(string: "https://www.google.de/maps/")!

urlComponents.queryItems = [
  NSURLQueryItem(name: "q", value: String(51.500833)+","+String(-0.141944)),
  NSURLQueryItem(name: "z", value: String(6))
]
urlComponents.URL // returns https://www.google.de/maps/?q=51.500833,-0.141944&z=6

글꼴 : https://www.ralfebert.de/snippets/ios/encoding-nsurl-get-parameters/


5
Rob의 인상적인 대답에도 불구하고 귀하의 대답은 더 간단하고 작동합니다.
1 월 ATAC

3
이것은 받아 들여진 대답이어야합니다. URL을 구성하기 위해 쿼리 항목과 함께 NSURLComponents를 사용하는 것이 좋습니다. 훨씬 안전하고 오류가 적습니다.
John Rogers

5

나는 이것을 사용하고 있습니다. 놀이터에서 시도해보십시오. 상수의 구조체로 기본 URL 정의

struct Constants {

    struct APIDetails {
        static let APIScheme = "https"
        static let APIHost = "restcountries.eu"
        static let APIPath = "/rest/v1/alpha/"
    }
}

private func createURLFromParameters(parameters: [String:Any], pathparam: String?) -> URL {

    var components = URLComponents()
    components.scheme = Constants.APIDetails.APIScheme
    components.host   = Constants.APIDetails.APIHost
    components.path   = Constants.APIDetails.APIPath
    if let paramPath = pathparam {
        components.path = Constants.APIDetails.APIPath + "\(paramPath)"
    }
    if !parameters.isEmpty {
        components.queryItems = [URLQueryItem]()
        for (key, value) in parameters {
            let queryItem = URLQueryItem(name: key, value: "\(value)")
            components.queryItems!.append(queryItem)
        }
    }

    return components.url!
}

let url = createURLFromParameters(parameters: ["fullText" : "true"], pathparam: "IN")

//Result url= https://restcountries.eu/rest/v1/alpha/IN?fullText=true

1

스위프트 3 :

extension URL {
    func getQueryItemValueForKey(key: String) -> String? {
        guard let components = NSURLComponents(url: self, resolvingAgainstBaseURL: false) else {
              return nil
        }

        guard let queryItems = components.queryItems else { return nil }
     return queryItems.filter {
                 $0.name.lowercased() == key.lowercased()
                 }.first?.value
    }
}

나는의 이미지 이름을 얻기 위해 그것을 사용 UIImagePickerControllerfunc imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]):

var originalFilename = ""
if let url = info[UIImagePickerControllerReferenceURL] as? URL, let imageIdentifier = url.getQueryItemValueForKey(key: "id") {
    originalFilename = imageIdentifier + ".png"
    print("file name : \(originalFilename)")
}

당신의 응답은 작전의 질문에 대답하지 않습니다
일리아스 카림에게

0

키와 값이 모두 다음과 같은 경우 Dictionary에만 제공 하도록 확장 할 수 있습니다.stringFromHttpParameterCustomStringConvertable

extension Dictionary where Key : CustomStringConvertible, Value : CustomStringConvertible {
  func stringFromHttpParameters() -> String {
    var parametersString = ""
    for (key, value) in self {
      parametersString += key.description + "=" + value.description + "&"
    }
    return parametersString
  }
}

이것은 훨씬 더 깨끗하고 stringFromHttpParameters해당 메서드를 호출하는 비즈니스가없는 사전 에 대한 우발적 인 호출을 방지합니다.


-1

@Rob이 제안한이 확장은 Swift 3.0.1에서 작동합니다.

Xcode 8.1 (8B62)로 그의 게시물에 포함 된 버전을 컴파일 할 수 없었습니다.

extension Dictionary {

    /// Build string representation of HTTP parameter dictionary of keys and objects
    ///
    /// :returns: String representation in the form of key1=value1&key2=value2 where the keys and values are percent escaped

    func stringFromHttpParameters() -> String {

        var parametersString = ""
        for (key, value) in self {
            if let key = key as? String,
               let value = value as? String {
                parametersString = parametersString + key + "=" + value + "&"
            }
        }
        parametersString = parametersString.substring(to: parametersString.index(before: parametersString.endIndex))
        return parametersString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
    }

}

-3

나는 사용한다:

let dictionary = ["method":"login_user",
                  "cel":mobile.text!
                  "password":password.text!] as  Dictionary<String,String>

for (key, value) in dictionary {
    data=data+"&"+key+"="+value
    }

request.HTTPBody = data.dataUsingEncoding(NSUTF8StringEncoding);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.