1
0
hugo/content/blog/2023-07-08-cors.md
2024-04-23 22:21:26 +09:00

111 lines
3.4 KiB
Markdown

+++
date = "2023-07-08"
tags = ["heroku"]
title = "cors-originのerrorを回避するためのproxyを変えた"
slug = "cors"
+++
今までherokuでcors-originのerrorを回避するためにproxy-serverを立ててたんだけど、やめた。これ一つのために`$7`かかってた。
> Access to fetch at 'http://localhost:3000/' from origin 'http://127.0.0.1:8080'
> 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.
https://developer.mozilla.org/ja/docs/Web/HTTP/CORS/Errors/CORSMissingAllowOrigin
このerrorは、例えば、apiのgetが同一のurlで行われていないことが要因です。
ですから、vueなら以下のようにproxyで同一url内であることを偽装すれば回避できます。
```js:vue.config.js
module.exports = {
devServer: {
proxy: {
"^/api*": {
target: "https://api.example.com",
pathRewrite: { "^/api": "" },
}
}
}
}
```
```js:src/App.vue
axios
.get("/api/test")
//.get("https://api.example.com/test")
.then(response => (this.data = response));
```
ただし、この回避方法はあくまでlocal, previewのみであり、`$ yarn build`などの`./dist`出力には適用されません。
これを解決する方法としては、apiに`Access-Control-Allow-Origin:"*"`を設定すること、あるいはproxy-serverを立てて経由することです。
```js
.get("https://proxy.heroku.com/https://api.example.com/test")
```
ent(ogent)でheaderを`Access-Control-Allow-Origin:"*"`にする方法ですが、一つずつ設定していくらしい。基本的にはupdate, deleteとかは使わないのでそれ以外のところに書きます。
```go:ent/ogent/oas_response_encoders_gen.go
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Content-Type", "application/json")
```
securityを考慮して特定のサイトのみを許可したほうがいいので、その場合は、vue-devserver-proxyと合わせて、以下のようにします。
```go:ent/ogent/oas_response_encoders_gen.go
func encodeReadUserResponse(response ReadUserRes, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Access-Control-Allow-Origin", "https://example.com")
}
```
```js:src/App.vue
data () {
return {
api_url: null,
}
},
mounted() {
if (window.location.host === "localhost:8080") {
this.api_url = "/api/";
} else {
this.api_url = "https://api.example.com/";
}
let url = this.api_url + "users";
axios.get(url,{ crossdomain: true })
.then(response => (this.data = response));
}
```
もし自前で運用するなら費用のかからないcloudflare zero-turst(tunnel)がいいと思います。
```sh:/ent/systemd/system/cors.service
[Unit]
Description=cors service
Documentation=https://github.com/Rob--W/cors-anywhere
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/home/syui/github/cors-anywhere
ExecStart=/usr/bin/node server.js
ExecStop=/usr/bin/pkill node
[Install]
WantedBy=default.target
```
```sh
$ git clone https://github.com/Rob--W/cors-anywhere
$ npm i
$ node server
$ sudo systemctl start cors
```
```sh
# これでAccess-Control-Allow-Originが設定されてたらok
$ curl --dump-header - 'https://api.example.com' -H 'Origin: https://example.com'
```