結論から言うと
SSRで前画面からPOSTされたパラメータを受け取る方法について、最初は馬鹿正直に
export const getServerSideProps: async (context: GetServerSidePropsContext) => {
// 注:この方法じゃGETパラメータは取れるけどPOSTパラメータは取れません
const query = context.query;
const param = query.param;
...
}
とかやって取れるのかと思ってたんだけど全然取得できず、どうやって取るのかなーと色々試行錯誤していた。で、色々ググったところ、こちらのissueにたどり着いた。タイトルの方法に関しては、ここで公開されている内容にほぼ完ぺきな回答がある。一部抜粋して転記させていただくと、以下の通りである。これでPOSTパラメータが取れる。
...
const streamPromise = new Promise( ( resolve, reject ) => {
let postBody = '';
req.on( 'data', ( data ) => {
// convert Buffer to string
postBody += data.toString();
} );
req.on( 'end', () => {
const postData = qs.parse( postBody );
resolve(postData);
} );
} );
...
const {
username,
password,
} = await streamPromise;
props.username = username;
props.password = password;
この例では username
と password
というパラメータをPOSTしてもらって、それを getServerSideProps
の中で取り出している。
若干修正
が、上の実装例にはちょっと難があって、というのも
- 処理が共通化されていないため、POSTパラメータを必要とする全ての
getServerSideProps
に同じ処理を書く必要がある - 型の定義がないのでTypescriptにそのままコピペすると
const {username, password} = await streamPromise;
の部分は警告が出る - というかそもそも
qs.parse
(querystring.parse
) はNode.js v14以降でdeprecatedである
といった点で修正が必要だった。まあ1点目はこの処理取り出して別のところに移せばいいのでそんな難しい話ではないのだが、3点目とそれに絡んで2点目(型をどうするか)でちょっと悩んだ。ググってみた感じ、querystring
の代替えとしては URLSearchParams
を使うのが一般的らしい。というわけで上の処理を取り出して個人的に共通化してみたのが以下。
import type { IncomingMessage } from "http";
import { URLSearchParams } from "url";
export default async function parsePostParam(req:IncomingMessage): Promise<URLSearchParams> {
return new Promise<URLSearchParams>( ( resolve, reject ) => {
let postBody = '';
req.on( 'data', ( data ) => {
// convert Buffer to string
postBody += data.toString();
} );
req.on( 'end', () => {
const postData = new URLSearchParams(postBody);
resolve(postData);
} );
} );
}
ほとんど上と同じである。違うのは引数と戻り値の型を決め打ちしていること。引数は IncomingMessage
で、これは GetServerSidePropsContext.req
をそのまま渡すことを想定している。戻り値は Promise<URLSearchParams>
になっているので、呼び出し元からは await
付けて呼んで URLSearchParams
を返してもらって使う。ちなみに呼び出し側からは以下のように呼び出して使う。
export const getServerSideProps: async (context: GetServerSidePropsContext) => {
const urlSearchParams = await parsePostParam(context.req);
const p1 = urlSearchParams.get('p1'); // POSTパラメータ名 "p1" の値を取り出す
...
}
ただ、戻りの型を URLSearchParams
にしちゃってるのでパラメータの取り出しには get
を使う必要があるのが若干イケてない気はする。querystring.parse
の戻り値と同じで params.name
みたいにアクセスできるほうがなんかしっくりくる。ような気はする。これをいい感じにその辺をまとめてるクラスみたいのをラップしてあげればその辺解決しそうだな、と思ったけど、面倒くさいのと実質これで動いてるからいいやと思うことにした。
なお元のコードも↑の修正例も、例外処理は一切入ってないのでその辺は各自良しなに、という感じで。。
以上