【问题标题】:swift http request can't get non-200 response快速 http 请求无法获得非 200 响应
【发布时间】:2016-07-10 21:18:59
【问题描述】:

我正在使用以下 swift 代码发出 http 请求。如果服务器响应 200 OK 响应,则 swift 可以正常工作。但是,当服务器响应不是 200 状态时,completionHandler 回调永远不会被调用,直到超时。 swift上有没有其他设置可以防止收到其他状态响应?

let urlStr = "http://xxxxx"
let url = NSURL(string: urlStr)!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "post"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {(data, response, error) in
    guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
                // no response code
        print("response")
        return
    }
    print("get response from register service \(data) \(error)")         
})
task.resume()

如果发生这种情况,我会在下面收到超时错误:

get login response nil error:Optional(Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSErrorFailingURLStringKey=http://XXXXX, NSErrorFailingURLKey=http://localhost:8080/nurse/login, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2103, NSLocalizedDescription=请求超时。})

我还使用 curl 命令进行了测试,得到了如下响应。所以服务器端对我来说很好。我相信问题出在客户端。

$ curl -i -X POST -d 'mobile=1234' http://localhost:8080/nurse/login
HTTP/1.1 10029 
Server: Apache-Coyote/1.1
X-Application-Context: application
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: access_token
Content-Type: text/plain;charset=UTF-8
Content-Length: 18
Date: Thu, 24 Mar 2016 02:39:09 GMT

【问题讨论】:

  • 你的错误变量说明了什么?
  • 它说超时。看到这个:获取登录响应零错误:可选(错误域=NSURLErrorDomain Code=-1001“请求超时。” UserInfo={NSErrorFailingURLStringKey=localhost:8080/nurse/login,NSErrorFailingURLKey=localhost:8080/nurse/login,_kCFStreamErrorDomainKey=4,_kCFStreamErrorCodeKey=-2103, NSLocalizedDescription=请求超时。})
  • 您的服务器可能没有发送非 2xx 响应。
  • @diatrevolo 我已经通过浏览器和邮递员验证我的服务器确实发送了非 200 响应。
  • @user3069232:我从未听说过 NSMutableURLRequest 会消失。我刚刚读到 NSURLConnection 消失并被共享会话取代。

标签: ios swift


【解决方案1】:

这似乎是服务器端问题。下面的代码有效(在 Playground 中):

尝试使用此网址,看看您是否会遇到这种情况。

另外,在调试 Swift 代码之前,我会使用 curl 等简单工具手动测试您的服务器端:

curl -i -X POST -d 'name=yoyo' http://putsreq.com/vccZnwiNpP23RF7nwOPE

编辑

这是一个功能,可以满足您的需求。我对您的 URL 进行了硬编码,现在一切正常。

func postSomeStuff(data: String, completion: (data: NSData?, error: NSError?)->Void) {

    let post: NSString = "data=\(data)"
    let url = NSURL(string: "http://123.56.184.207:8080/nurse/login")!
    let postData = post.dataUsingEncoding(NSUTF8StringEncoding)!

    let postLength = String(postData.length)

    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "POST"
    request.HTTPBody = postData
    request.setValue(postLength, forHTTPHeaderField: "Content-Length")
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.setValue("*/*", forHTTPHeaderField: "Accept")

    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    config.timeoutIntervalForRequest = 120
    config.timeoutIntervalForResource = 240

    let session = NSURLSession(configuration: config)

    let task = session.dataTaskWithRequest(request) { urlData, response, reponseError in

        if let receivedData = urlData {
            let res = response as! NSHTTPURLResponse!;

            NSLog("Response code: %ld", res.statusCode);

            if 200..<300 ~= res.statusCode {
                completion(data: receivedData, error: nil)
            } else {
                let returnedError = NSError(domain: "getSomeStuff", code: 1, userInfo: [:])
                completion(data: nil, error: returnedError)
            }
        } else {
            var userInfo: [NSObject: AnyObject] = [:]
            if let error = reponseError {
                userInfo["message"] = error.localizedDescription
                userInfo["cause"] = error
            }
            let returnedError = NSError(domain: "myFunc", code: 2, userInfo: userInfo)
            completion(data: nil, error: returnedError)
        }
    }
    task.resume()
}

postSomeStuff("yoyo") { data , err in
    if let data = data { print(data) }
    if let err = err { print(err) }
}

let sema = dispatch_semaphore_create(0);
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);


// Used only in Playground
XCPSetExecutionShouldContinueIndefinitely(true)

【讨论】:

  • 我只是运行 curl 并立即得到响应。请看下面的输出。状态为 10029。 localhost:cooltoo_backend yzzhao$ curl -i -X POST -d 'mobile=1234' localhost:8080/nurse/login HTTP/1.1 10029 服务器:Apache-Coyote/1.1 X-Application-Context: application Access-Control-Allow-来源:* Access-Control-Allow-Methods:* Access-Control-Allow-Headers:access_token 内容类型:text/plain;charset=UTF-8 内容长度:18 日期:2016 年 3 月 24 日星期四 02:39: 09 GMT
  • 为了清楚起见,我在我原来的问题上添加了输出,请看一下。
  • 我发布了对我的回复的编辑,其中包含一些可以满足您需求的示例代码。
  • 感谢您向我展示代码。我已经在我的操场上运行了你的代码,但我仍然面临这个问题。服务器端有响应,但 xcode 在超时之前无法获得响应。或者你可以尝试用上面的代码访问这个链接:123.56.184.207:8080/nurse/login
  • 我在关闭 VPN 后工作得很好。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-22
  • 1970-01-01
相关资源
最近更新 更多