CORS Spec 、GET、およびPOSTリクエストは302リダイレクトに透過的に続く必要がありますが、Chromeはリクエストをキャンセルしています。
リクエストを行うJSは次のとおりです。
var r = new XMLHttpRequest();
r.open('GET', 'https://dev.mysite.com/rest', true);
r.send();
起こるべきことは次のとおりです。
しかし、ステップ2の後、Chromeはリクエストをキャンセルします。HTTP302がなかった場合、リクエストは完全に機能します。これを確認しました。
リクエストを実行すると、Chromeの[ネットワーク]パネルには1つのXHRのみが表示されます。キャンセルされたPOSTレスポンスヘッダーまたはレスポンス本文のないリクエスト。
Chromeのnet-internalsツールを使用してデバッグすると、サーバーから応答が送信されたことがわかります。その後、要求はキャンセルされました。リクエストの出力は次のとおりです。
79295: URL_REQUEST
https://dev.mysite.com/rest
Start Time: 2013-08-30 12:41:11.637
t=1377880871637 [st= 0] +REQUEST_ALIVE [dt=13455]
t=1377880871638 [st= 1] URL_REQUEST_BLOCKED_ON_DELEGATE [dt=1]
--> delegate = "extension Adblock Plus"
t=1377880871639 [st= 2] +URL_REQUEST_START_JOB [dt=13453]
--> load_flags = 143540480 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | ENABLE_LOAD_TIMING | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)
--> method = "POST"
--> priority = 2
--> upload_id = "0"
--> url = "https://dev.mysite.com/rest"
t=1377880871639 [st= 2] HTTP_CACHE_GET_BACKEND [dt=0]
t=1377880871639 [st= 2] +HTTP_STREAM_REQUEST [dt=7]
t=1377880871646 [st= 9] HTTP_STREAM_REQUEST_BOUND_TO_JOB
--> source_dependency = 79296 (HTTP_STREAM_JOB)
t=1377880871646 [st= 9] -HTTP_STREAM_REQUEST
t=1377880871646 [st= 9] +HTTP_TRANSACTION_SEND_REQUEST [dt=0]
t=1377880871646 [st= 9] HTTP_TRANSACTION_SEND_REQUEST_HEADERS
--> GET /facultyportfolio-rest HTTP/1.1
Host: dev.liberty.edu
Connection: keep-alive
Content-Length: 46
Origin: http://localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.62 Safari/537.36
Content-Type: application/json; charset=UTF-8
Accept: */*
Referer: http://localhost:8080/ajaxtest.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
t=1377880871646 [st= 9] HTTP_TRANSACTION_SEND_REQUEST_BODY
--> did_merge = true
--> is_chunked = false
--> length = 46
t=1377880871646 [st= 9] -HTTP_TRANSACTION_SEND_REQUEST
t=1377880871646 [st= 9] +HTTP_TRANSACTION_READ_HEADERS [dt=1001]
t=1377880871646 [st= 9] HTTP_STREAM_PARSER_READ_HEADERS [dt=1000]
t=1377880872646 [st= 1009] HTTP_TRANSACTION_READ_RESPONSE_HEADERS
--> HTTP/1.1 302 Found
Date: Fri, 30 Aug 2013 16:41:11 GMT
Server: Apache/2
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Credentials: true
Location: https://dev.mysite.com/rest/
Content-Language: en-US
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 20
Connection: close
Content-Type: text/plain; charset=UTF-8
t=1377880872647 [st= 1010] -HTTP_TRANSACTION_READ_HEADERS
t=1377880872647 [st= 1010] +URL_REQUEST_BLOCKED_ON_DELEGATE [dt=12445]
t=1377880885091 [st=13454] CANCELLED
t=1377880885092 [st=13455] -URL_REQUEST_START_JOB
--> net_error = -3 (ERR_ABORTED)
t=1377880885092 [st=13455] -REQUEST_ALIVE
最後に、「URL_REQUEST_BLOCKED_ON_DELEGATE」により「Cancelled」が表示されます。それが何を意味するのか分かりません。ただし、HTTP 302リダイレクトがなければ、エラーは発生しません。
Chromeがこのリクエストをキャンセルする原因は何ですか?
ここでの答えは混合されており、コードなどの特定の設定を示唆しているため、CORSのリダイレクトの問題を解決できる可能性がありますが、CORS仕様ではそのようなCORSリダイレクトが失敗/成功するタイミングを明確に指定しています:仕様に従って、ブラウザは
手動リダイレクトフラグが設定されておらず、応答のHTTPステータスコードが301、302、303、307、または308の場合リダイレクト手順を適用する
応答のHTTPステータスコードが301、302、303、307、または308の場合キャッシュとネットワークエラーの手順を適用します。
GithubリポジトリでさまざまなCORSシナリオを調査しました: https://github.com/monmohan/cors-experiment 。
リダイレクトの失敗に関するこの特定の問題は、バンドルによって個別に簡単に再現することもできます: https://github.com/monmohan/cors-experiment/tree/master/issue
2応答に正しいAccess-Control-Allow-Origin CORSヘッダーを設定する についてのこの投稿が見つかりました(少なくとも私の似たような音の場合)。
この問題を調査したところ、彼のXHRはCORS対応のURLに直接到達していなかったが、HTTP 302(リダイレクト)応答を介してそのURLにリダイレクトされていました。
したがって、リダイレクトURLにはAccess-Control-Allow-Originヘッダーも含める必要があります。そうしないと、ブラウザーはクロスドメインリクエストを試みてそこで停止します。
また、Access-Control-Allow-Origin以上の追加のCORSヘッダーを設定すると、トランザクションがキャンセルされることがよくあることもわかりました。
GETまたはHEAD以外のリクエストに応答して302ステータスコードを受信した場合、ユーザーが確認できない限り、ユーザーエージェントはリクエストを自動的にリダイレクトしてはなりません。リクエストが発行された条件が変わる可能性があるためです。
また、ChromeがCORSリクエストのリダイレクトに従っていないという問題もありました。私にとって問題は、使用するJSフレームワーク(Sencha Touch)がリクエストヘッダーを追加することです:X-Requested -With: "XMLHttpRequest"
これを削除すると(Sencha TouchでExt.Ajax.setUseDefaultXhrHeader(false);を呼び出して)、チャームのように機能しました。
理由はわかりませんが、この情報が誰かに役立つことを願っています。