Swift-4:如何使用带有“Content-Type”的 URLSession 中的参数的 POST 请求获取数据:“application/x-www-form-urlencoded”

Posted

技术标签:

【中文标题】Swift-4:如何使用带有“Content-Type”的 URLSession 中的参数的 POST 请求获取数据:“application/x-www-form-urlencoded”【英文标题】:Swift-4 : How to fetch data using POST request with Parameters in URLSession with "Content-Type" : "application/x-www-form-urlencoded" 【发布时间】:2018-11-20 07:48:21 【问题描述】:

朋友们,我已经浏览了很多示例,这些示例可在 S.O.虽然我没有收到正确的答案,但我仍然面临使用带有 Post 请求的 URLSession 通过 api 请求获取数据并传递参数的问题。

首先,我想告诉你,我有什么。尝试到现在...

func requestApiCall()

    let renewal_id = ""
    let policy_no = ""
    let client_name = ""
    let client_id = ""
    let product_name = ""
    let created_date_from = ""
    let created_date_to = ""
    let policy_expiry_from = ""
    let policy_expiry_to = ""

    self.parameters = ["renewal_id":renewal_id,"policy_no":policy_no,"client_name":client_name,"client_id":client_id,"product_name":product_name,"created_date_from":created_date_from,"created_date_to":created_date_to,"policy_expiry_from":policy_expiry_from,"policy_expiry_to":policy_expiry_to]

    let config = URLSessionConfiguration.default
    config.httpAdditionalHeaders = [
        "Accept" : "application/json",
        "Content-Type" : "application/x-www-form-urlencoded"
    ]
    let session = URLSession(configuration: config)
    let Url = String(format: "http://myapi-url");
    let serviceUrl = URL(string: Url)
    var request = URLRequest(url: serviceUrl!)
    print(request.url!)
    request.httpMethod = "POST"
    request.timeoutInterval = 60

    request.httpBody  = try! JSONSerialization.data(withJSONObject: parameters!, options: [])

    let task = session.dataTask(with: request as URLRequest, completionHandler: data, response, error -> Void in

        if error == nil
            print(response!)
        
        else 
            print(error?.localizedDescription as Any)
        

        print(response!)
        guard let httpResponse = response as? HTTPURLResponse, let receivedData = data
            else 
                print("error: not a valid http response")
                return
        

        switch (httpResponse.statusCode)
        
        case 200: //The request was fulfilled
            let response = NSString (data: receivedData, encoding: String.Encoding.utf8.rawValue)

            if response == "SUCCESS"
            
                print("Network - HandShaking Successfull...!!!")
            
            else
                print("Network - HandShaking is not successfull...!!!")
            

        case 400:
            print("response-status - 400 : The request had bad syntax or was inherently impossible to be satisfied.")
        case 500:
            print("\nresponse-status - 500 : Internal Server Error...!!!")
        default:
            print("response-status - Unknown : Received Response =>  \(httpResponse.statusCode)")
        
    )
    task.resume()

运行上述函数后,我得到 httpResponse.statusCode = 500

但是当我在邮递员中运行它时,我得到了正确的响应。

Postman Api-Request

我也尝试过通过邮递员生成code-sn-ps...如下...

func postmanSnippetApiCall()
    let headers = [
        "Content-Type": "application/x-www-form-urlencoded",
        "cache-control": "no-cache",
        "Postman-Token": "5d571157-86c5-4eac-ba6d-b00779ae5dbd"
    ]

    let postData = NSMutableData(data: "renewal_id=".data(using: String.Encoding.utf8)!)
    postData.append("&policy_no=".data(using: String.Encoding.utf8)!)
    postData.append("&client_name=".data(using: String.Encoding.utf8)!)
    postData.append("&client_id=".data(using: String.Encoding.utf8)!)
    postData.append("&product_name=".data(using: String.Encoding.utf8)!)
    postData.append("&created_date_from=".data(using: String.Encoding.utf8)!)
    postData.append("&created_date_to=".data(using: String.Encoding.utf8)!)
    postData.append("&policy_expiry_from=".data(using: String.Encoding.utf8)!)
    postData.append("&policy_expiry_to=".data(using: String.Encoding.utf8)!)
    postData.append("&undefined=undefined".data(using: String.Encoding.utf8)!)

    let request = NSMutableURLRequest(url: NSURL(string: "http://myapiurl")! as URL,
                                      cachePolicy: .useProtocolCachePolicy,
                                      timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler:  (data, response, error) -> Void in
        if (error != nil) 
            print(error)
         else 
            let httpResponse = response as? HTTPURLResponse
            print(httpResponse)
        
    )

    dataTask.resume()

但是在 postman 生成的代码 sn-p 中,我在这一行收到错误,即 request.httpBody = postData as Dataerror 是这个:Cannot convert value of type 'NSMutableData' to type 'Data' in coercion

如果我使用第三方库,即 Alamofire,那么我可以很容易地获取数据。

Alamofire 代码 sn-p...完美运行..& 给出正确响应。

func apiRequestByAlamofire()
        let urlString = "http://myapiurl"

        let params: [String: Any]? = ["renewal_id":"","policy_no":"","client_name":"","client_id":"","product_name":"","created_date_from":"","created_date_to":"","policy_expiry_from":"","policy_expiry_to":""]

        Alamofire.request(urlString, method: .post, parameters: params).responseJSON  response in
            print(response) //Here getting perfect response successfully...!!!
        

    

但我仍然在通过 URLSession 苦苦挣扎......!!!

我仍然怀疑,为什么我在使用 URLSession 时遇到了太多问题。

以上疑惑的朋友们,请我接受您的建议,并请帮助我理解它。

不知道,我哪里错了。请帮帮我。

【问题讨论】:

postman中有生成Code sn-ps的选项,试试看。 是的,我也尝试过...但无法解决。获取响应状态为 500。 如果您尝试使用 Postman 生成的 Objective-C 代码,它不起作用? 嗨 @Larme 你能帮我解决这个问题吗? @Larme 是的,它确实有效 【参考方案1】:

经过大量搜索和斗争,我想出了这个解决方案:

        guard var components = URLComponents(url: URL(string: "http://example.com")!, resolvingAgainstBaseURL: true)
            else  fatalError("Couldn't create URLComponents") 
        
        components.queryItems = params.map  k, v in URLQueryItem(name: k, value: v) 
        
        var request = URLRequest(url: baseUrl.appendingPathComponent(path.rawValue))
        request.httpBody = Data(components.query!.utf8)
        request.httpMethod = "POST"

“example.com”实际上可以是这样,因为我只是使用URLComponents 对参数进行编码。

【讨论】:

【参考方案2】:

我给你简单的功能,你可以根据你的要求编辑这个功能。您也可以更改 URL 和参数。在响应中,如果您从服务器获取 JSON 数组,我已经写了两行,如果您正在获取对象,则使用第一行,然后第二行删除这两行。

func abc()  
    let request = NSMutableURLRequest(url: URL(string: "Your URL")!)
    request.httpMethod = "POST"
    let postString = "param_name_one=\( value_1 )&param_name_two=\(value_2)&........."
    request.httpBody = postString.data(using: String.Encoding.utf8)
    let task = URLSession.shared.dataTask(with: request as URLRequest) 
        data, response, error in
        if(error != nil)
            // Show Error Message
         else
            do 
                //For JSON ARRAY
                let jsonItem  = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! NSArray
                let json = jsonItem[0] as AnyObject
               //For JSON object 
                let json_object  = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as AnyObject
                print(json_object)
                
             catch 
                
            
        
    
    task.resume();

【讨论】:

不,我没有收到数据,但是是的,我收到了状态码 200,但还没有响应。我发送的参数只有键,没有价值。 这只是获取数据的技术,请尝试在服务器端调试您的代码并根据您的响应编辑您的问题,无论您从服务器获得什么。您可以为此使用 PostMan。或向您的后端开发人员寻求指导。 但在 Alamofire 中,我可以正确获取数据。那么 URLSession 有什么问题 尝试打印您的响应,然后尝试打印下一阶段的数据!,只有调试是最好的解决方案,因为相同的代码正在我的系统上运行。

以上是关于Swift-4:如何使用带有“Content-Type”的 URLSession 中的参数的 POST 请求获取数据:“application/x-www-form-urlencoded”的主要内容,如果未能解决你的问题,请参考以下文章

Swift 4 - 如何使用按钮启用/禁用键盘

Swift 4 可编码;如何使用单个根级密钥解码对象

Swift 4 - 使用 PromiseKit 调用嵌套

使用 DispatchGroup、DispatchQueue 和 DispatchSemaphore 按顺序执行带有 for 循环的 Swift 4 异步调用

带有可配置键的 Swift 4 JSON 解码

swift 带有Swift 4 ios应用程序填充的圆形视图