Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

CORS(preflight request)にハマったけど解決した話

CORS(preflight request)にハマったので、解決方法を備忘録として残しておきます。

エラーが起きた場面

異なるドメインからHttpリクエストを送る場合は、CORSに注意だよなぁ。
サーバー側のレスポンスで、ヘッダーをつけてあげれば良いんだろう。
簡単じゃん。

クライアント側

何かしらのデータをjasonでPOSTする。

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", API_ENDPOINT);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.send(JSON.stringify(data));

APIサーバー側

サーバー側では、レスポンスのヘッダーを付けてあげる。

func (a *API) HandleFunc(w http.ResponseWriter, r *http.Request) {
    //略...

    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
    w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")

    //略...

    fmt.Fprint(w, "ok")
}

結果、エラー...!

当然、結果が正常に返ってくると思いきや
プリフライトリクエスト?がどうのこうのといったエラーが出た。。。なんやこれ。。。

Access to XMLHttpRequest at 'http://localhost:8080/api' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

CORS(preflight request)エラー解決

preflight requestとは?

リクエストによっては CORS プリフライトを引き起こさないものがあります。これをこの記事では「単純リクエスト」と呼んでいますが、 (CORS を定義している) Fetch 仕様書ではこの用語を使用していません。 「単純リクエスト」は、以下のすべての条件を満たすものです。
・許可されているメソッドのうちの一つであること。
GET
HEAD
POST
・ユーザーエージェントによって自動的に設定されたヘッダー (たとえば Connection、 User-Agent、 または Fetch 仕様書で「禁止ヘッダー名」として定義されているヘッダー) を除いて、手動で設定できるヘッダーは、 Fetch 仕様書で「CORS セーフリストリクエストヘッダー」として定義されている以下のヘッダーだけです。
Accept
Accept-Language
Content-Language
Content-Type (但し、下記の要件を満たすもの)
DPR
Downlink
Save-Data
Viewport-Width
Width
・Content-Type ヘッダーでは以下の値のみが許可されています。
application/x-www-form-urlencoded
multipart/form-data
text/plain
・リクエストに使用されるどの XMLHttpRequestUpload にもイベントリスナーが登録されていないこと。これらは正しく XMLHttpRequest.upload を使用してアクセスされます。
・リクエストに ReadableStream オブジェクトが使用されていないこと。
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#Preflighted_requests

上記の条件を満たさないものはpreflight requestがメインのリクエストの前に行われます。
今回は、POSTですが、"Content-Type", "application/json"をヘッダーに付けているので、プリフライトリクエストが起きました。
画像の最初のリクエストがpreflight requestです。
ここでは、実際にはOPTIONSメソッドがpreflight requestとして走ります。
preflight_correct.png

解決方法

 OPTIONSメソッドの時は、http.StatusOKを返すようにしたら解決しました!

func (a *API) HandleFunc(w http.ResponseWriter, r *http.Request) {
    //略...

    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
    w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")

    if r.Method == "OPTIONS" {
        w.WriteHeader(http.StatusOK)
        return
    }
    //略...

    fmt.Fprint(w, "ok")
}
laughingman
都内エンジニア。SalesforceやTwilioを主に触っています。よろしくお願いします。
https://note.mu/kota_en
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away