我遇到了一个奇怪的问题,即新创建的URLSessionUploadTask
会立即被取消。我不确定它是否是目前Xcode 8测试版的错误。
我怀疑它可能是一个错误,因为我即将发布的代码只运行一次。之后没有对它进行任何更改,然后它就停止了工作。是的,它实际上只运行一次,然后停止工作。我会在最后发布错误。
我将在下面发布代码,但首先我将总结这里的逻辑是如何工作的。
我的测试或用户公开的API(用于Playgrounds或直接在应用程序中使用的IE)调用authorize
方法。此authorize
方法将依次调用buildPOSTTask
,这将构建有效的网址并返回URLSessionUploadTask
方法使用的authorize
。
话虽如此,代码如下:
会议:
internal let urlSession = URLSession(configuration: .default)
创建上传任务的功能:
internal func buildPOSTTask(onURLSession urlSession: URLSession, appendingPath path: String, withPostParameters postParams: [String : String]?, getParameters getParams: [String : String]?, httpHeaders: [String : String]?, completionHandler completion: URLSessionUploadTaskCompletionHandler) -> URLSessionUploadTask {
let fullURL: URL
if let gets = getParams {
fullURL = buildURL(appendingPath: path, withGetParameters: gets)
} else {
fullURL = URL(string: path, relativeTo: baseURL)!
}
var request = URLRequest(url: fullURL)
request.httpMethod = "POST"
var postParameters: Data? = nil
if let posts = postParams {
do {
postParameters = try JSONSerialization.data(withJSONObject: posts, options: [])
} catch let error as NSError {
fatalError("[\(#function) \(#line)]: Could not build POST task: \(error.localizedDescription)")
}
}
let postTask = urlSession.uploadTask(with: request, from: postParameters, completionHandler: completion)
return postTask
}
身份验证功能,它使用上述功能创建的任务:
public func authorize(withCode code: String?, completion: AccessTokenExchangeCompletionHandler) {
// I have removed a lot of irrelevant code here, such as the dictionary building code, to make this snippet shorter.
let obtainTokenTask = buildPOSTTask(onURLSession: self.urlSession, appendingPath: "auth/access_token", withPostParameters: nil, getParameters: body, httpHeaders: nil) { (data, response, error) in
if let err = error {
completion(error: err)
} else {
print("Response is \(response)")
completion(error: nil)
}
}
obtainTokenTask.resume()
}
我在测试中发现了这个错误:
let testUser = Anilist(grantType: grant, name: "Test Session")
let exp = expectation(withDescription: "Waiting for authorization")
testUser.authorize(withCode: "a valid code") { (error) in
if let er = error {
XCTFail("Authentication error: \(er.localizedDescription)")
}
exp.fulfill()
}
self.waitForExpectations(withTimeout: 5) { (err) in
if let error = err {
XCTFail(error.localizedDescription)
}
}
此错误始终会立即失败:
错误域= NSURLErrorDomain代码= -999“已取消”UserInfo = {NSErrorFailingURLKey = https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED, NSLocalizedDescription =取消, NSErrorFailingURLStringKey = https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED}
以下是一些需要注意的事项:
以下是我尝试的一系列事项:
cancel
,我还重写了authorize
以返回由{{1}创建的任务并将其分配给我的测试中的变量。任务仍然被取消。我还没有尝试的事情(但是当我解决这些问题时,我会接受任何其他想法):
我不知道该尝试什么。生成的日志似乎没有任何有用的信息。
我决定在这里发布整个项目。完成时,事情将是开源的,我获得的API凭据是用于测试应用程序。
答案 0 :(得分:7)
经过6天不间断的挣扎,在谷歌搜索不停的解决方案之后,我真的很开心说我终于弄明白了。
我们认为,无论出于何种神秘原因,from:
中的uploadTask(with:from:completionHandler)
参数都不能为零。尽管参数被标记为可选Data
,但它在缺失时会立即被取消。这可能是Apple的一个错误,当我无法解决这个问题时,我发现了一个错误,因此我将使用这些新信息更新我的错误报告。
话虽如此,我所要做的就是更新我的buildPOSTTask
方法,以解释传递的字典为零的可能性。有了它,它现在工作正常:
internal func buildPOSTTask(onURLSession urlSession: URLSession, appendingPath path: String, withPostParameters postParams: [String : String]?, getParameters getParams: [String : String]?, httpHeaders: [String : String]?, completionHandler completion: URLSessionUploadTaskCompletionHandler) -> URLSessionUploadTask {
let fullURL: URL
if let gets = getParams {
fullURL = buildURL(appendingPath: path, withGetParameters: gets)
} else {
fullURL = URL(string: path, relativeTo: baseURL)!
}
var request = URLRequest(url: fullURL)
request.httpMethod = "POST"
var postParameters: Data
if let posts = postParams {
do {
postParameters = try JSONSerialization.data(withJSONObject: posts, options: [])
} catch let error as NSError {
fatalError("[\(#function) \(#line)]: Could not build POST task: \(error.localizedDescription)")
}
} else {
postParameters = Data()
}
let postTask = urlSession.uploadTask(with: request, from: postParameters, completionHandler: completion)
return postTask
}
答案 1 :(得分:0)
您的服务器坏了..
tcp_connection_cancel 1
nw_socket_handle_socket_event Event mask: 0x4
nw_socket_handle_socket_event Socket received WRITE_CLOSE event
nw_endpoint_handler_cancel [1 anilist.co:443 ready resolver (satisfied)]
nw_endpoint_handler_cancel [1.1 104.28.1.44:443 ready socket-flow (satisfied)]
__nw_socket_service_writes_block_invoke sendmsg(fd 9, 31 bytes): socket has been closed
nw_endpoint_flow_protocol_error [1.1
104.28.1.44:443 cancelled socket-flow (null)] Socket protocol sent error: [32] Broken pipe
nw_endpoint_flow_protocol_disconnected [1.1 104.28.1.44:443 cancelled socket-flow (null)] Output protocol disconnected
nw_endpoint_handler_cancel [1.2 104.28.0.44:443 initial path (null)]
nw_resolver_cancel_on_queue 0x60800010da40
[NWConcrete_tcp_connection dealloc] 1
[User Defaults] CFPrefsPlistSource<0x6180000f8700> (Domain: XIO.PrivateAPITest, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null)) is waiting for writes to complete so it can determine if new data is available
它无限期地等待“写”完成..
它发送请求..进行SSL握手并且没有响应。它超时并认为它是一个破碎的请求..
class WTF : NSObject, URLSessionDelegate {
var urlSession: URLSession!
override init() {
super.init()
urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
var request = URLRequest(url: URL(string: "https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED")!)
request.httpMethod = "POST"
let data = try! JSONSerialization.data(withJSONObject: ["Test":"Test"], options: [])
urlSession.uploadTask(with: request, from: data).resume()
}
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(.performDefaultHandling, nil)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: NSError?) {
}
func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: (URLRequest?) -> Void) {
completionHandler(request)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: (URLSession.ResponseDisposition) -> Void) {
completionHandler(.allow)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
}
}
答案 2 :(得分:0)
您是否有机会使用Ensighten这样的第三方库?我在XCode 8 beta中遇到了完全相同的问题(在XCode 7中运行正常),所有带有nil参数的块都导致崩溃。事实证明,正在进行某种编码的库导致了这个问题。