ミルク色の記録

やったこと、やってみたこと

極力バックエンドを書かずに異なるドメインのWebサイトからデータを取得するCORS Proxyというのを作った

作ったと言っても、実際コードを書いたのは2年近く前だったのだけど。

当時書いてたアプリのために作っておいたのをずっと放置していたが、最近ちょっと使う用途があったので久しぶりに触ったら何もかも忘れてて(README書いてなかった)えらい苦労した。改めて使い方調べながらREADMEまとめたので、ついでに気づいたバグとか直してGitHubで公開した。

github.com

CORSとは

Cross-Origin Resource Sharing (CORS) は、追加の HTTP ヘッダーを使って、あるオリジン (ドメイン) で動いているウェブアプリケーションが、異なるオリジンのサーバーのリソースにアクセスできるようにする仕組み

引用: MDN Web docs オリジン間リソース共有 (CORS)

雑に説明すると、サーバ側でAccess-Control-Allow-Originヘッダーをレスポンスで返してなんやかんやするやつ。

今回作ったやつは追加のリクエストヘッダーをいくつか必要としているので、Access-Control-Allow-Headersヘッダーのレスポンスやプリフライトリクエスト(OPTIONSメソッドのリクエストが本命の前に実行される)への対応も必要になっている。

使い方

環境準備

Herokuで動かすようにしてあるので、リポジトリをクローンしたらHerokuアプリケーション作って、認証用の環境変数を設定してデプロイする。

$ git clone https://github.com/ushiboy/cors-proxy
$ cd cors-proxy
$ heroku create

認証用のキーはbin/generate_keyでランダムに生成する。

$ bin/generate_key
[Key]: tV4VWOcq0HbJ...
[Digest]: $2y$10$do7go...

認証用の環境変数AUTH_KEY_DIGESTに生成したDigestの値を、ALLOW_ORIGINに許可するオリジン(複数指定する場合はカンマで区切る)を設定する。

$ heroku config:set AUTH_KEY_DIGEST='$2y$10$do7go...' ALLOW_ORIGIN=http://myapp.com

プッシュしてデプロイする。

$ git push heroku master

Webフロントエンド側からの利用

デプロイ先のHerokuアプリケーションのURLに、生成した認証用のKeyの方をAuthorizationリクエストヘッダーにBearerとしてつけて、クエリストリングのqパラメータに取得対象のURLを指定してリクエストを発行する。

const q = encodeURIComponent('http://www.example.com/data.txt');
const result = await fetch(`https://<your_app_name>.herokuapp.com/?q=${q}`, {
  headers: {
    'Authorization': `Bearer tV4VWOcq0HbJ...`
  }
});

これでプリフライトリクエストのあとに正しく取得ができれば動作はOK。

取得対象が古のCP932とかCP51932とかUTF-8ではない場合はX-From-Charsetヘッダーをつけてリクエストすることで、UTF-8エンコードして取得できる。

const q = encodeURIComponent('http://www.example.com/data.txt');
const result = await fetch(`https://<your_app_name>.herokuapp.com/?q=${q}`, {
  headers: {
    'Authorization': `Bearer tV4VWOcq0HbJ...`,
    'X-From-Charset': 'CP51932'
  }
});

X-From-Charsetに指定できる文字コードの種類はPHPmbstringがサポートしてるやつ。

補足

認証キーとオリジンでアクセス制限するようにしているけど、これは気休め程度。Webフロントエンド以外のところでやろうと思えばどうにでもできるので、フロントエンドのコードにベタ書きして使うかは要検討。

自分はHerokuアプリケーションのURLと認証キーをローカルストレージに設定するようにしてコードにベタ書きはせずに使ってる。

GETしかできないものなので、そこまで気にしなくても良いかも...という気もしないでもない。

とりあえずちょっと外部Webサイトのリソースも使いたいWebアプリ書くとかだったら、フロントエンド側はGithub Pagesでホストしてそこから利用するとかできると思う。