在NSMutableURLRequest中设置body不起作用

时间:2017-03-03 12:02:08

标签: swift post swift3 nsurlrequest

部首:

let header = ["Content-Type" : "application/x-www-form-urlencoded", "Authorization" : "Basic " + self.basicAuth];

体:

var body : [String : AnyObject] = [:];
let body = ["grant_type" : "client_credentials", "scope" : "MessageSender"];

请求和序列化:

private func makeHTTPPostRequest(path: String, header: [String : String], body: [String: AnyObject], onCompletion: @escaping ServiceResponse) {
        let request = NSMutableURLRequest(url: NSURL(string: path)! as URL)

        // Set the method to POST
        request.httpMethod = "POST"

        do {
            // Set the POST body for the request
            let jsonBody = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
            request.httpBody = jsonBody
            let session = URLSession.shared
            request.allHTTPHeaderFields = header;

            let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
                if let httpResponse = response as? HTTPURLResponse {
                    if let jsonData = data {
                        let json:JSON = JSON(data: jsonData)
                        print(response)
                        print(json)
                        onCompletion(json,httpResponse, error as NSError?)
                    } else {
                        onCompletion(JSON.null,HTTPURLResponse.init(), error as NSError?)
                    }
                }

            })
            task.resume()
        } catch {
            onCompletion(JSON.null,HTTPURLResponse.init(), nil)
        }
    }
}

请求完成后,会触发400响应 { "error_description" : "grant_type parameter is requiered field and it has to be non empty string.", "error" : "invalid_request" }

显然身体设置不正确,但我真的不知道为什么。我在其他应用程序中使用这段代码没有问题.... 同样的要求就像邮差中的魅力一样。邮递员的身体设置为x-www-form-urlencoded类型。 也许JSONSerialization错了?

1 个答案:

答案 0 :(得分:0)

要使用Content-Type: application/x-www-form-urlencoded;发送POST请求,您需要创建类似URL查询的字符串,然后将其转换为数据。您的代码或任何Swift标准库函数都没有该功能。您可能需要自己编写,或找到合适的第三方库。 (当然JSONSerialization不适用于此,String不是JSON。)

给定Dictionary<String, String>,您可以这样做:

var body: [String: String] = [:]
body = ["grant_type": "client_credentials", "scope": "MessageSender"]

(简体...)

request.httpBody = body.map{"\($0)=\($1)"}.joined(separator: "&").data(using: .utf8)
//`body.map{"\($0)=\($1)"}.joined(separator: "&")` -> grant_type=client_credentials&scope=MessageSender

(严格...... 4.10.22.6 URL-encoded form data

extension CharacterSet {
    static let wwwFormUrlencodedAllowed = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._*" + "+")
}

extension String {
    var wwwFormUrlencoded: String {
        return self
            .replacingOccurrences(of: " ", with: "+")
            .addingPercentEncoding(withAllowedCharacters: .wwwFormUrlencodedAllowed)!
    }
}

class HTTPBody {
    static func wwwFormUrlencodedData(withDictionary dict: [String: String]) -> Data {
        return body
            .map{"\($0.wwwFormUrlencoded)=\($1.wwwFormUrlencoded)"}
            .joined(separator: "&").data(using: .utf8)!
    }
}

request.httpBody = HTTPBody.wwwFormUrlencodedData(withDictionary: body)

(请记住,没有多少服务器将接收到的表单数据解释为严格生成。)

在这种情况下,这不是一个关键问题,但你应该更好地使用Swift类而不是NS-

typealias  ServiceResponse = (JSON, HTTPURLResponse?, Error?)->Void

private func makeHTTPPostRequest(path: String, header: [String : String], body: [String: String], onCompletion: @escaping ServiceResponse) {
    var request = URLRequest(url: URL(string: path)!)

    // Set the method to POST
    request.httpMethod = "POST"

    // Set the POST body for the request (assuming your server likes strict form data)
    request.httpBody = HTTPBody.wwwFormUrlencodedData(withDictionary: body)
    let session = URLSession.shared
    request.allHTTPHeaderFields = header;

    let task = session.dataTask(with: request, completionHandler: {data, response, error -> Void in
        if let httpResponse = response as? HTTPURLResponse {
            if let jsonData = data {
                let json:JSON = JSON(data: jsonData)
                print(response)
                print(json)
                onCompletion(json, httpResponse, error)
            } else {
                onCompletion(JSON.null, httpResponse, error)
            }
        }
    })
    task.resume()
}