【Next.js】getServerSidePropsをリバースプロキシ化して遊ぼう
はじめに
Next.js には SSR するための getServerSideProps と SSG/ISR のための getStaticProps というデータフェッチファンクションが用意されています。
一般的な getServerSideProps
は、次のようにレンダリングに必要な props を返却することが主な用途です。
export async function getServerSideProps(context) {
const data = await fetch('...').then((res) => res.json())
return {
props: data
}
}
この使い方は非常に一般的なものであり、Next.js ユーザならほとんどの人が知っていることでしょう。
しかし、getServerSideProps
の拡張性に関してはあまり一般的には知られていないようです。
引数である context
は Node HTTPServer の req
と res
を内包しています。
これは、setHeader
を通じてレスポンスを書き換えたり、pipe
を使ってストリームを取り扱うことが可能であるということを示唆しており、getServerSideProps
そのものが HTTPServer のリゾルバとして機能させられるとうことでもあります。
それでは早速、getServerSideProps
をリバースプロキシとして稼働させる例を通じて、その拡張性を確認していきましょう。
リバースプロキシ
リバースプロキシのコードはこちらを参考にさせていただきました。
getServerSideProps をリバースプロキシ化する
前項で紹介したリバースプロキシのコードを getServerSideProps
に組み込みます。
// pages/proxy.ts
import { VFC } from 'react'
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
import https, { RequestOptions } from 'https'
import http from 'http'
export const proxy = (
{ req, res }: GetServerSidePropsContext,
options: RequestOptions,
isSecure?: boolean
): Promise<void> => {
return new Promise((resolve) => {
const serverReq = (isSecure ? https : http)
.request(options)
.on('error', () => res.writeHead(502).end())
.on('timeout', () => res.writeHead(504).end())
.on('response', (serverRes) => {
res.writeHead(serverRes.statusCode ?? 200, serverRes.headers)
serverRes.pipe(res)
})
.on('close', resolve)
req.pipe(serverReq)
})
}
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const host = typeof ctx.query.host === 'string' ? ctx.query.host : 'localhost'
const path = typeof ctx.query.path === 'string' ? ctx.query.path : '/'
await proxy(
ctx,
{
host,
path
},
true
)
return {
props: {}
}
}
const Dummy: VFC = () => null
export default Dummy
このように、getServerSideProps
の req
を http(s).request
にパイプすることで、リクエスをリバースプロキシに流しています。
さらにレスポンスを getServerSideProps
の res
にパイプすることで、再度 getServerSideProps
側で処理できるようにするというのが大まかな処理の流れです。
また、pages 配下のファイルは、コンポネントを default export する必要があるため、ダミーの空コンポネントを用意していますが、こちらが処理されることはありません。
ローカルでサーバーを立ち上げ、http://localhost:3000/proxy?host=example.com
でアクセスした結果がこちらです。
https://example.comとおなじコンテンツが表示されることが確認できました。
まとめ
タイトル通り、getServerSideProps
をリバースプロキシ化することに成功しました。
Node HTTPServer の実装が多少理解できれば、getServerSideProps
の拡張は簡単に行なえます。
もし Next.js でトリッキーな実装を行わなければいけなくなった際には、ぜひ挑戦してみてください。
ちなみに
ファイルをPOSTでアップロードしたり、JSONデータをレスポンスとして取り扱ったりするのであれば、元も子もありませんが API Routes を使用すべきです。
どんなケースでこの getServerSideProps
の拡張が必要なのかということに関しては、A/BテストをCDNベースで行うためのプラグインで、実際にこのリバースプロキシ化を活用していますので、興味がある方は参照してみてください。
かんたんに紹介しておくと、rewrites
で A/Bテスト対象のパスをプロキシページに転送し、リバースプロキシによってオリジナル用とチャレンジャ用のページを出し分けるということをしています。
また、つい先日このようなのプラグインも発見したので、こちらも紹介しておきます。
こちらは、リクエストメソッドに応じた処理を書き分けることを可能にするプラグインです。
Discussion