带参数的Swift GET请求

时间:2014-12-31 16:48:47

标签: ios swift get nsurlrequest

我对swift很新,所以我的代码可能会有很多错误,但我想要实现的是向带有参数的localhost服务器发送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)

    }

}

7 个答案:

答案 0 :(得分:108)

在构建GET请求时,请求没有正文,而是所有内容都在URL上。要构建URL(以及正确转义它的百分比),您还可以使用URLComponents

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

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

唯一的诀窍是大多数Web服务需要转义+个字符百分比(因为它们会将其解释为application/x-www-form-urlencoded specification所指示的空格字符)。但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的基本思路。


请参阅previous revision of this answer了解Swift 2和手动百分比转义格式。

答案 1 :(得分:85)

使用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
  

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

答案 2 :(得分:4)

我正在使用它,在操场上试试。将基本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

答案 3 :(得分:2)

Swift 3

template<class T> void relaxmax(T& r, T v) { r = max(r, v); }

vector<int> dp(n + 1);
vector<int> C(n + 1, -INF);
vector<int> q(n + 1);
vector<int> ne(n + 1, -INF);
int qback = 0, qfront = 0;
auto cmp = [&](const int& x, const int& y) {
    int vx = dp[x] + C[x], vy = dp[y] + C[y];
    return vx != vy ? vx < vy : x < y;
};
set<int, decltype(cmp)> s(cmp);

dp[0] = 0;
s.insert(0);
q[qfront++] = 0;

for (int i = 1; i <= n; ++i) {
    C[i] = A[i - 1];
    auto it_last = lower_bound(q.begin() + qback, q.begin() + qfront, i, [=](const int& x, const int& y) {
        return C[x] > C[y];
    });

    for (auto it = it_last; it != q.begin() + qfront; ++it) {
        s.erase(*it);
        C[*it] = A[i - 1];
        ne[*it] = i;
        if (it == it_last) s.insert(*it);
    }

    dp[i] = dp[*s.begin()] + C[*s.begin()];

    while (qback < qfront && dp[q[qfront]] >= dp[i]) {
        s.erase(q[qfront]);
        qfront--;
    }

    q[qfront++] = i;
    C[i] = -INF;
    s.insert(i);

    if (q[qback] == i - k) {
        s.erase(i - k);

        if (qback + 1 != qfront && ne[q[qback]] > q[qback + 1]) {
            s.erase(q[qback + 1]);
            relaxmax(C[q[qback + 1]], C[i - k]);
            s.insert(q[qback + 1]);
        }

        qback++;
    }
}

// answer: dp[n]

我用它来获取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 } } 中的UIImagePickerController的图片名称:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])

答案 4 :(得分:0)

@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)!
    }

}

答案 5 :(得分:0)

如果密钥和值都符合此类Dictionary,则您可以将stringFromHttpParameter扩展为仅提供CustomStringConvertable

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进行意外调用

答案 6 :(得分:-1)

我用:

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