JavaScript
Go
api
golang
CORS

Go言語(Go-Json-Rest)のCORSでのハマり。Safariだけでハマった話。

More than 3 years have passed since last update.

go-json-restを使ってAPIサーバーを立ててCORS対応する話を前に書いたのですが、Safariだけ挙動でハマった話です。

参考: Go言語(Go-Json-Rest)でAPIサーバーを立てるときのCORS設定 (Basic認証機能付きも)

ハマり内容

前のコードと同じ内容です。
ChromeやFirefoxの場合はこれで問題無く動作していました。

  • Go側
app.go

/*省略*/
  api.Use(&rest.CorsMiddleware{
        RejectNonCorsRequests: false,
        OriginValidator: func(origin string, request *rest.Request) bool {
            return origin == "http://localhost:3000" || origin == "http://192.168.43.158:3000" || origin == "http://localhost"
        },
        AllowedMethods: []string{"GET", "POST", "OPTIONS"},
        AllowedHeaders: []string{"Accept","Authorization","content-type"},
        AccessControlAllowCredentials: true,
        AccessControlMaxAge:           3600,
    })

/*省略*/

  • フロント側
api.js
$(function(){
  var host = 'localhost:8080';
  var rand_param = '?ie=' + parseInt((new Date())/1000, 10);
  var endpoint = '/countries';
  var url = 'http://'+host+endpoint+rand_param;

  function make_base_auth(user, password) {
    var tok = user + ':' + password;
    var hash = btoa(tok);
    return "Basic " + hash;
  }

  $.ajax({
      url: url,
      beforeSend: function (xhr){
        xhr.setRequestHeader('Authorization', make_base_auth('userud', 'password'));
      },
  }).done(function(data){
      console.log(data);
  }).fail(function(data){
      console.log(data);
  });

});

ここまでは前回と同様のソースコードです。

chromeやfirefoxだと普通です。

safariだけでエラーが発生。(しかもPOSTのみ)

※ safariのバージョンは8.0.7(OSはYosemite)です。

iPhoneで確認して、最初はiPhoneだけの問題かと思いきや、Safari特有の問題みたいです。

※ GETメソッドは問題無く動作してました。

解決: Access-Control-Allow-Headersにoriginを追加しましょう。

色々試行錯誤した結果解決しました。

Access-Control-Allow-Headersにoriginを追加することで解決しました。逆に言えば、Safari以外はこの指定が無くても動いてくれるんですね。

go-json-restの実装の場合はAllowedHeadersoriginを追加します。これでsafariでも大丈夫です。

app.go

/*省略*/
AllowedHeaders: []string{"origin", "Accept","Authorization","content-type"},    
/*省略*/

これだけで半日くらいハマった...
Safariだけで発生した問題だったのでブラウザごとのxhr実装とかの関係かと思ってフロント側調査ばかりしてました。

こちらの記事(GolangでXMLHttpRequestLevel2+CORSのプリフライトが通るサーバーを立てる(BasicAuth付き))をもとにサーバーを構築しなおしてみたら同じJSコードで通ったのでGo側の実装に問題がありそうだという糸口です。

まとめ

GETメソッドは問題無く動作していたのでややこしかったです。
Access-Control-Allow-Headersはしっかり設定しましょう。

勉強になりました。→ 異なるドメインのURLからデータを参照する方法 - Cross-Origin Resource Sharing