WebpackのdevServerを使ってもサーバと通信できるフロント開発がしたい

はじめに

自分はReactやReduxを使ってWebアプリを開発するときにWebpackのdevServerにお世話になる。devServerを使えば、ソース変更時に自動でブラウザをリロードしてくれて便利だからである。

しかし、devServerを使った場合、localhostで動かしてるwebサーバと通信できない。たとえば、devServerは、http://localhost:8080で起動する。
そこから、http://localhost:8000で動作するwebサーバとHTTP通信することは異なるオリジンにアクセスすることになってしまい通信は失敗する。
localhost:8080とlocalhost:8000は、異なるオリジンなので前者から後者に対して通信することは普通できないのである。

ローカルでwebサーバを動かす一方でフロント開発でdevServerを使ってるとき、フロントがサーバからデータ取得できるようにするにはどうすればよいのだろうかと壁にぶつかった。異なるオリジンであっても通信できるようにするにはどうすればよいのだろうかということである。

なので今回は、異なるオリジンであってもサーバと通信できる設定について備忘録を残そうと思う。

目次

  1. expressで簡単なwebサーバの準備
  2. 同一オリジンから通信できることの確認
  3. 別オリジンから通信の失敗確認
  4. expressのCORS設定
  5. SessionありCORS

1. expressで簡単なwebサーバの準備

nodejsのexpressを使用する。
expressでのwebサーバ構築方法は、割愛させていただきます。

npm i -S expressでexpressをインストール
次のapp.jsを用意する。

app.js

const express = require('express');
const app = express();

// "/"にアクセスしたときにres.jsonの引数値を返す
app.get('/', (req, res) => {
  res.json({
    result: 'success',
    message: 'hello express',
  });
});

// 8000ポートで起動
const server = app.listen(8000, () => {
  console.log(`Node.js is listening to PORT: ${server.address().port}`);
});

あとは、node app.js(あるいはnpm scriptsに記述してnpm start)でサーバを起動させる。すると、http://localhost:8000にアクセスしたときにres.json()の引数に指定したjsonを受け取ることができる。

これでまずサーバサイドの実装は終了。

2. 同一オリジンから通信できることの確認

ブラウザを起動させ、urlにhttp://localhost:8000と入力すると、 先程のjsonが画面に表示される。

さらに、fetchメソッドも使って取得できることも確認しよう。
console画面に次を入力して取得できることを確認する。

fetch('/', {
  method: 'GET',
  headers: { 'content-type': 'appliaction/json' }
}).then(r => r.json()).then(r => { console.log(r); })

// コンソール出力値
// {result: "success", message: "hello express"}

3. 別オリジンから通信の失敗確認

グーグルトップページ(https://wwww.google.co.jp)を開いて、同じくコンソール画面に次を入力する

// ドメインが違うので、URLを省略せずに書く
fetch('http://localhost:8000', {
  method: 'GET',
  headers: { 'content-type': 'appliaction/json'}
}).then(r => r.json()).then(r => { console.log(r); })

fetchの第一引数は、http://localhost:8000になる。
"/"は、https://www.google.co.jpを意味するからだ。

その結果は次のとおりである。

f:id:poppon555:20181008204419p:plain

やはり、ドメインが異なるため通信失敗する。 エラー内容にある通り、HTTPリクエストのヘッダーに'Access-Control-Allow-Origin'が存在しないからダメだよと言われるている。(他にもヘッダーに足りない情報がある)

4. expressのCORS設定

異なるオリジンからの通信も許可するために、サーバサイドに変更を加える。

app.js

const express = require('express');
const app = express();

// ------------- ここから --------------
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', "*"); // (1)
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); // (2)
  res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS'); // (3)
  next();
});
// ------------- ここまで --------------

app.get('/', function(req, res) {
  res.json({
    result: 'success',
    message: 'hello express',
  });
});

const server = app.listen(8000, () => {
  console.log(`Node.js is listening to PORT: ${server.address().port}`);
});

追加した内容については、
(1): どんなオリジンからの通信を許可("*"はすべてを意味する)
(2): 指定するheader情報の通信を許可
  今回fetchメソッドでは、headersに'content-type': 'appliaction/json'を指定してるため
(3): GETからOPTIONSまでのHTTPメソッドを使って通信すること許可
ということになる。

これでもういちど、fetchメソッドを実行すると取得できるようになる(やったね)。

5. SessionありCORS(おまけ)

session情報をもたせるときは、もう少し改良が必要になる。 変更箇所のみ記述する

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', req.headers.origin); // (1)
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Credentials', true); // (2)
  next();
});

(1): "*"ではなく、リクエストからオリジン情報を取得し、そのからの通信を許可
(2): sessionを使うときはこれを追加してあげる
これでsessionありの通信も可能となるが、最後にフロントでのfetchメソッドも確認しておく。

fetch('http://localhost:8000', {
      method: 'GET',
      headers: { 'content-type': 'application/json' },
      credentials: 'include', // (3)
    }).then(r => r.json()).then(r => { console.log(r); })

(3)のとおり、credentailをfetchメソッドのオプションに追加する。

最後に

これでサーバと通信できるフロント開発ができるように助けになってくれれば幸いである。非常に駆け足で説明してきたので、かなり読みにくい文章になってしまった。申し訳ない(あとでもう少し読みやすくしようと思います。)

参考サイト

http://var.blog.jp/archives/60055220.html https://qiita.com/MuuKojima/items/2b2e7bc0db8d5e97ada9 https://blog.kazu69.net/2017/03/23/http-request-using-cors/