Netlify Functions を使って CORS 制限を回避する
Posts
webpack-dev-server は、webpack を用いた開発用サーバーを立てるためのモジュールです。 Netlify Functions は、Netlify の提供するアドオンのひとつで、 AWS Lambda を実行基盤にした FaaS(Function as a Service)です。
webpack-dev-server で立てた開発サーバーから Netlify Functions で立てたサーバーを呼び出すと、port が違うため CORS の同一オリジンポリシーの制約に引っかかります。
これを回避するには、webpack-dev-server のプロキシ機能を使います。
動作を確認した環境
- webpack-dev-server v3.9.0
- netlify-lambda v1.6.3
webpack の設定
:webpack.config.js
に次の設定を追記します。
module.exports = {
mode: "development",
// ... 省略 ...
devServer: {
proxy: {
'/.netlify': {
target: 'http://localhost:9000',
pathRewrite: { '^/.netlify/functions': '' }
}
}
}
}:
- webpack-dev-server に「/.netlify」へのリクエストが来たとき、Netlify Function のサーバー(
localhost:9000
)へフォワードします。 pathRewrite
の設定で、「/.netlify/functions」を取り除いた形でのリクエストをバックエンドに投げます。
おまけ:Nuxt.js の場合
Nuxt.js を使って作ったページで、axios を使って Netlify functions へリクエストを送ることを考えます。 Nuxt.js は v2.8.1 で確認しました。
Nuxt.js の設定ファイル nuxt.config.js
は次のように設定します。
module.exports = {
modules: [
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
generate: {
dir: 'dist/client'
},
axios: { baseURL: '/.netlify/functions' },
proxy: {
'/.netlify': {
target: 'http://localhost:9000',
pathRewrite: { '^/.netlify/functions': '' }
}
}
}
Nuxt.js でのページと Netlify Functions はこんな感じに作ります。
リクエストを送るページ
<template> <main> <input v-model="name" placeholder="Name"></input> <input v-model="message" maxlength="200" type="textarea"></input> <button @click="sendMessage">Send</button> </main> </template> <script> export default { data() { return { name: '', message: '' } }, methods: { async sendMessage() { const params = { name: this.name, message: this.message }; try { const resp = await this.$axios.post('/message', params); this.$router.push('/result'); } catch(e) { const message = e || 'Sorry, an error occurred.' window.alert(message); } } } } </script>
結果を表示するページ
<template> <main> <span>Thank you!</span> </main> </template> <script> export default { data() { return { } } } </script>
Netlify Functions の Lambda 関数
'use strict'; const fetch = require('node-fetch'); export const header = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true', 'content-type': 'application/json; charset=utf-8', }; exports.handler = async (event, context, callback) => { if (event.httpMethod !== 'POST') { callback(null, { statusCode: 503, headers: header, body: JSON.stringify({error: 'Method Not Allowed'}) }); } try { const data = JSON.parse(event.body); const options = { method: 'post', body: { name: data.name, message: data.message}, headers: {'Content-Type': 'application/json', 'X-EXAMPLE-Authorization': 'XXXXX'} }; const resp = await fetch('https://exmaple.com/api/v1/message', options); callback(null, { statusCode: 200, headers: header, body: JSON.stringify(resp) }); } catch(err) { callback(null, { statusCode: 500, headers: header, body: JSON.stringify(err) }); } };