{"id":18376209,"url":"https://github.com/bunji2/gocors","last_synced_at":"2025-04-11T04:42:17.686Z","repository":{"id":95709847,"uuid":"212354737","full_name":"bunji2/gocors","owner":"bunji2","description":"Sample of CORS using GoLang (described in Japanese)","archived":false,"fork":false,"pushed_at":"2020-04-27T06:49:27.000Z","size":152,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-11T04:42:14.528Z","etag":null,"topics":["cors","golang","http"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bunji2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-02T13:55:11.000Z","updated_at":"2020-04-27T06:49:30.000Z","dependencies_parsed_at":"2023-05-21T17:15:24.292Z","dependency_job_id":null,"html_url":"https://github.com/bunji2/gocors","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bunji2%2Fgocors","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bunji2%2Fgocors/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bunji2%2Fgocors/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bunji2%2Fgocors/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bunji2","download_url":"https://codeload.github.com/bunji2/gocors/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248345281,"owners_count":21088242,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cors","golang","http"],"created_at":"2024-11-06T00:22:15.398Z","updated_at":"2025-04-11T04:42:17.669Z","avatar_url":"https://github.com/bunji2.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gocors --- CORS (Cross-Origin Resource Sharing) の GoLang によるサンプル\r\n\r\nあるコンテンツが \"XMLHttpRequest\" を用いて WebAPI に対して JSON データを入出力としたアクセスすることを考える。\r\n\r\nGoLang では次の handlerAPI 関数のような実装を検討するはずだ。\r\n\r\n```\r\nfunc main() {\r\n\thttp.HandleFunc(\"aaa.jp/api\", handlerAPI)\r\n\thttp.ListenAndServe(port, nil)\r\n}\r\n\r\nfunc handlerAPI(w http.ResponseWriter, r *http.Request) {\r\n\t// POSTメソッド意外の場合は 405 を返す\r\n\tif r.Method != http.MethodPost {\r\n\t\tw.WriteHeader(http.StatusMethodNotAllowed)\r\n\t\treturn\r\n\t}\r\n\r\n\t// 返信データの用意\r\n\tretData := NewRetData()\r\n\r\n\t// JSON形式のパラメータを取得\r\n\tparam, err := getParamFromJSON(r)\r\n\r\n\t// パラメータの取得に成功したとき\r\n\tif err == nil {\r\n\t\t// calc の計算結果を返信データに設定\r\n\t\tretData.Status = \"OK\"\r\n\t\tretData.Value = calc(param.X, param.Y)\r\n\t}\r\n\r\n\tw.Header().Set(\"Content-Type\", \"application/json\")\r\n\r\n\t// JSON 形式でクライアントに返信\r\n\tfmt.Fprintf(w, `%s`, retData.JSONString())\r\n}\r\n```\r\n\r\nこの実装は \"Same-Origin Policy\" の条件を前提としている。\r\n\r\n![fig0](images/fig0.png)\r\n\r\nこの WebAPI を別のオリジンのコンテンツからも使う場合には、\"Same-Origin Policy\" を満たせずブラウザによりブロックされてしまう。\r\n\r\nその際に例えば Chrome では次のようなメッセージがコンソールに表示される。\r\n\r\n```\r\nAccess to XMLHttpRequest at 'http://aaa.jp:8080/api' from origin 'http://example.jp:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.\r\n```\r\n\r\nオリジンが 'example.jp' でここから XMLHttpRequest で 'aaa.jp' の WebAPI にアクセスする前に、\"preflight request\" が要求される。しかしそのレスポンスが \"CORS policy\" を満たさずブロックされてしまう。\r\n\r\n![fig1](images/fig1.png)\r\n\r\nクロスオリジンな状況でも WebAPI を提供できるようにするには、ブラウザが要求する \"preflight request\" に対してオリジンを許可するレスポンスを返す必要がある。\r\n\r\n必要なレスポンスヘッダを以下に示す。\r\n\r\n|レスポンスヘッダ|概要|\r\n|:--|:--|\r\n|Access-Control-Allow-Origin|アクセスを許容するオリジン|\r\n|Access-Control-Allow-Methods|アクセスを許容するメソッド群|\r\n|Access-Control-Allow-Headers|アクセスを許容するヘッダ群|\r\n\r\n以下にレスポンスヘッダの例を示す。\r\n\r\n```\r\nAccess-Control-Allow-Origin: http://example.jp:8080\r\nAccess-Control-Allow-Methods: POST, OPTIONS\r\nAccess-Control-Allow-Headers: Content-Type\r\n```\r\n\r\n\"Access-Control-Allow-Methods\" で WebAPI 用の \"POST\" メソッドと \"preflight request\" 用の \"OPTIONS\" メソッドを追加している。また、WebAPI の入力データのコンテンツタイプ用に \"Access-Control-Allow-Headers\" で \"Content-Type\" を指定する。\r\n\r\n通常、同一オリジンで使用する WebAPI ならば上記のように \"POST\" メソッドのみ実装すればよいが、クロスオリジンで使用するには \"preflight request\" に応答できなければならない。以下に \"preflight request\" への対応するため先の実装を修正する。\r\n\r\n```\r\nfunc main() {\r\n\t// http.HandleFunc(\"aaa.jp/api\", handlerAPI)\r\n\thttp.HandleFunc(\"aaa.jp/api\", handlerAPIWithCORS)\r\n\thttp.ListenAndServe(port, nil)\r\n}\r\n\r\nfunc handlerAPI(w http.ResponseWriter, r *http.Request) {\r\n    // 省略\r\n}\r\n\r\nfunc handlerAPIWithCORS(w http.ResponseWriter, r *http.Request) {\r\n\t// Origin ヘッダのチェック\r\n\tif !IsAllowableOrigin(r) {\r\n\t\t// Origin を許容できない場合は 403 を返す\r\n\t\tw.WriteHeader(http.StatusForbidden)\r\n\t\treturn\r\n\t}\r\n\r\n\t// OPTIONS メソッドのときは preflight request を処理して終了。\r\n\tif r.Method == http.MethodOptions {\r\n\t\tprocessPreFlightRequest(w, r)\r\n\t\treturn\r\n\t}\r\n\r\n\t// handlerAPI のレスポンスにオリジンを許容するヘッダを追加する。\r\n\tw.Header().Set(\"Access-Control-Allow-Origin\", r.Header.Get(\"Origin\"))\r\n\r\n\t// API 処理の呼び出し\r\n\thandlerAPI(w, r)\r\n}\r\n\r\nfunc processPreFlightRequest(w http.ResponseWriter, r *http.Request) {\r\n\t// クライアントからの Origin を許容する\r\n\tw.Header().Set(\"Access-Control-Allow-Origin\", r.Header.Get(\"Origin\"))\r\n\tw.Header().Set(\"Access-Control-Allow-Methods\", \"POST, OPTIONS\")\r\n\tw.Header().Set(\"Access-Control-Allow-Headers\", \"Content-Type\")\r\n}\r\n\r\n```\r\n\r\n\"handlerAPIWithCORS\" 関数は \"handlerAPI\" 関数をラップする。重要なポイントは以下の二点である。\r\n\r\n* \"OPTIONS\" メソッドの場合 \"processPreFlightRequest\" 関数により、\"preflight request\" に対してオリジンを許可するレスポンスを返す。\r\n\r\n* \"handlerAPI\" 関数のレスポンスにオリジンを許可するヘッダを追加する。\r\n\r\n![fig2](images/fig2.png)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbunji2%2Fgocors","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbunji2%2Fgocors","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbunji2%2Fgocors/lists"}