新しく作成されたURLSessionUploadTask
が即座にキャンセルされるという奇妙な問題が発生しています。 Xcode8の現在のベータ版のバグかどうかはわかりません。
投稿しようとしているコードが1回だけ正常に実行されたため、バグの可能性があると思われます。その後、変更は加えられず、単に動作を停止しました。はい、文字通り一度実行した後、動作を停止しました。エラーは終わり近くに投稿します。
以下のコードを投稿しますが、最初にここでのロジックがどのように機能するかを要約します。
私のテスト、またはユーザー公開API(Playgroundsまたはアプリで直接使用するためのIE)は、authorize
メソッドを呼び出します。このauthorize
メソッドは次にbuildPOSTTask
を呼び出します。これにより、有効なURLが作成され、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 = cancelled、NSErrorFailingURLStringKey = https://anilist.co/api/auth/access_token?client_secret = REMOVED&grant_type = authorization_code&redirect_uri = genericwebsitethatshouldntexist -hod6w&code = REMOVED }
覚えておくべきことがいくつかあります。
これが私が試したことのリストです:
cancel
を呼び出して、authorize
を書き直してbuildPOSTTask
そしてそれを私のテストの変数に割り当てました。タスクはまだキャンセルされていました。私がまだ試したことのないこと(しかし、これらを処理するときに他のアイデアを受け入れます):
私は何を試すべきかについての考えがありません。生成されたログには有用な情報がないようです。
プロジェクト全体をここに投稿することにしました。とにかく終了するとオープンソースになります。取得したAPI認証情報はテストアプリ用です。
これで6日間ノンストップで苦労し、解決策をノンストップでグーグルした後、私は本当に幸せです私はついにそれを理解したと言います。
不思議な理由が何であれ、uploadTask(with:from:completionHandler)
のfrom:
パラメーターをnilにすることはできません。パラメータがオプションのData
としてマークされているにもかかわらず、パラメータが欠落しているとすぐにキャンセルされます。これはおそらくApple側のバグであり、これを機能させることができなかったときにバグを開いたので、この新しい情報でバグレポートを更新します。
そうは言っても、私がしなければならなかったのは、渡された辞書がnilになる可能性を考慮して、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
}
サーバーが壊れています。
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) {
}
}
万が一、Ensightenなどのサードパーティライブラリを使用していますか? XCode 8ベータ版でもまったく同じ問題が発生し(XCode 7では正常に機能します)、パラメーターがnilのブロックがすべてクラッシュしていました。問題の原因は、ライブラリが何らかのエンコードを行っていたことが判明しました。