LoginSignup
0
0

More than 1 year has passed since last update.

【Next.js】SSRでPOSTパラメータを取得する方法

Posted at

結論から言うと

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;

この例では usernamepassword というパラメータをPOSTしてもらって、それを getServerSideProps の中で取り出している。

若干修正

が、上の実装例にはちょっと難があって、というのも

  1. 処理が共通化されていないため、POSTパラメータを必要とする全ての getServerSideProps に同じ処理を書く必要がある
  2. 型の定義がないのでTypescriptにそのままコピペすると const {username, password} = await streamPromise; の部分は警告が出る
  3. というかそもそも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 みたいにアクセスできるほうがなんかしっくりくる。ような気はする。これをいい感じにその辺をまとめてるクラスみたいのをラップしてあげればその辺解決しそうだな、と思ったけど、面倒くさいのと実質これで動いてるからいいやと思うことにした。
なお元のコードも↑の修正例も、例外処理は一切入ってないのでその辺は各自良しなに、という感じで。。

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0