CORSを解決してローカル環境で2つのサービスを動かしたい
ブラウザのWebページから、別サーバのWebAPIを呼び出すという動作検証を両方ローカル環境でやりたい、というのが今回の趣旨です。
次のような2つのサービスを用意して、ローカル環境で動作させます。
サービス | URL |
---|---|
Webページ | localhost:5000で起動。アクセスするとWebAPIを呼び出す。 |
WebAPI | localhost:8000で起動 |
初回コード(これは失敗します)
まず最初に作ったのは次のようなコードです。
ブラウザサービス側(localhost:5000)
window.onload = function() { const data = { name: 'example' }; fetch('http://localhost:8000') .then(response => response.json()) .then(data => {console.log(data);}) .catch(function(error) { console.log("error:", error); }); }
WebAPI側(localhost:8000)
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, User{ Name: "hoge", }) }) r.Run(":8000") }
これを両方とも起動して、ブラウザサービスにアクセスするとWebAPIが呼び出されるのですが、CORSの問題で次の通りアクセスエラーが起きます。
Access to fetch at 'http://localhost:8000/' from origin 'http://localhost:5000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
最終コード(これで解決しました)
色々調べた結果、WebAPI側で「Access-Control-Allow-Origin」レスポンスヘッダを付ければいいということが大枠で分かりました。
goで実装しているWebAPIはginを使っているのですが、CORSを解決してくれるパッケージがあるようなのでそれを使って解決しました。
こちらのサイトを参考にしています。
http://psychedelicnekopunch.com/archives/820
WebAPI側(localhost:8000)を改造
package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // CORS 対応を追加 config := cors.DefaultConfig() config.AllowOrigins = []string{"http://localhost:5000"} r.Use(cors.New(config)) r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, User{ Name: "hoge", }) }) r.Run(":8000") }
やってみたけど駄目だったこと
この先は解決に至るまでに色々試行錯誤していた内容を載せておきます。
最初、fetchを使ったCORSの解決方法を探していて、こちらのサイトmodeを指定できることを知りました。 https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch
リクエストヘッダのmodeは"no-cors", "cors", "same-origin"を指定できるのですが、"no-cors"を使えばとりあえず動くかな?と思い、設定してみました。
ブラウザサービス側(localhost:5000)を改造
window.onload = function() { const data = { name: 'example' }; fetch('http://localhost:8000', { method: 'GET', mode: "no-cors", headers: { 'Content-Type': 'application/json'}, }) .then(response => response.json()) .then(data => {console.log(data);}) .catch(function(error) { console.log("error:", error); }); }
この方法は、WebAPIは呼べるようになるのですが、受け取ったデータにjsonデータが含まれなくなります。 結局これだとレスポンスデータを受け取れなくなるようです。 さらに上のリンクのサイトにも次のように注意書きがありました。
なお、
mode: "no-cors"
はリクエスト中の限られた数のヘッダーにしか許可されていません。
- Accept
- Accept-Language
- Content-Language
- Content-Type のうち、値が application/x-www-form-urlencoded, multipart/form-data, text/plain のいずれかのもの