Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9050

文字コードを指定してURLエンコードを行う(Node.js)

$
0
0
文字コードを指定してURLエンコードしたい。日本語(が含まれるん)だもの。 そういう話です。 encodeURI()はUTF-8を表すエスケープシーケンスで置換される Node.jsを用いて、あるAPIをGETメソッドでリクエストする処理を実装していました。 そのAPIはクエリストリングを APIの名前?key1=value1&key2=value2&signature=認証用の値 にしてリクエスト送信してくださいね、ということで下記のようなソースでクエリストリングを作成。 // 例えばユーザーの情報を取得するAPI // API名称 const apiName = 'getUser'; // リクエスト内容 const params = { name : '則巻アラレ', age : 13 } /** * クエリストリングを作成する * @param {String} apiName API名称 * @param {Object} params リクエスト内容 * @returns クエリストリング */ function makeQueryString(apiName, params) { let queryString = `${apiName}?`; // リクエスト内容分ループ for (const key in params) { const value = params[key]; // 値 queryString += `${key}=${value}&`; } // 末尾に認証用の値を付与 queryString += `signature=xxx`; // URLエンコード return encodeURI(queryString); } // クエリストリングの作成 const queryString = makeQueryString(apiName, params); しかし、encodeURI()1を用いてURLエンコードを行ったクエリストリングを使って、GETリクエストを送信しても、該当ユーザーがいない、というレスポンスばかりが返ってきていました。ぴえん (該当するnameとageを持つユーザーは作成したのに!) 認証エラーが返ってきていないので、認証は通っている...。 何がダメなんだ?とそのAPIの開発者向けドキュメントを再読すると、以下の記述。 ドキュメントさん「Windows-31JでURLエンコードを行ってください」 私「OK Google、Windows-31Jとは」 文字コード CP932 / Windows-31J CP932とは、日本語の文字などを収録した文字コード規格の一つで、Shift JIS規格を元にマイクロソフト(Microsoft)社が独自に拡張したもの。微妙に異なる複数の仕様がある。 〔......〕同社(注: Microsoft社)はCP932のインターネット上での識別名としてIANAに「Windows-31J」を登録し〔......〕 CP932とは - IT用語辞典 ぶっちゃけこの文字コード初めて聞いたな...と思いつつ、 encodeURI()について確認すると、確かにrepresenting the UTF-8 encoding of the character2と記載があるので、UTF-8の文字を表すエスケープシーケンスで置換されるようです。 先ほどのコードだと、以下クエリストリングは getUser?name=則巻アラレ&age=13&signature=xxx encodeURI()によって、以下に変換されます。 name部分は、UTF-8の文字を表す(らしい)エスケープシーケンスで置換されています。 getUser?name=%E5%89%87%E5%B7%BB%E3%82%A2%E3%83%A9%E3%83%AC&age=13&signature=xxx 今回は、URLエンコードが行われた文字列を、Windows-31Jの文字列として表す必要があるので、標準の関数は使えないですね 文字コードを指定してURLエンコードができるiconv-urlencode やっと本題。 UTF-8以外の文字コードを指定してURLエンコードを行わなければならない!!!という方が世界にもいたのでしょう。 iconv-urlencodeというパッケージを用いることで、それが可能です。 上記サイトの説明によると、iconv-liteパッケージで指定可能な文字コード3であれば、URLエンコード/デコード可能なようです。Shift_JIS, Windows-31j等が使用可能です。 以下の実行環境で実施していきます。 $ node --version v14.17.4 $ npm --version 6.14.14 インストール。 npm install iconv-urlencode あとは先ほどのソースコードに、モジュールの読み込みを追加し、 関数内で作成したクエリストリングをURLエンコードして返すようにします。 const conv = require('iconv-urlencode'); const encoding = 'Windows-31j'; // 文字コード // ...... // 略 // ...... function makeQueryString(apiName, params) { let queryString = `${apiName}?`; // リクエスト内容分ループ for (const key in params) { const value = params[key]; // 値 queryString += `${key}=${value}&`; } // 末尾に認証用の値を付与 queryString += `signature=xxx`; // 文字コードを指定し、URLエンコード return conv.encode(queryString, encoding); // iconv-urlencodeを利用 } ...と上記ソースコードだと実行結果がこうなります。 # getUser?name=則巻アラレ&age=13&signature=xxx のURLエンコード結果 getUser%3Fname%3D%91%A5%8A%AA%83A%83%89%83%8C%26age%3D13%26signature%3Dxxx 今回は?, =, &は変換されてほしくないので、修正。 値のみURLエンコードするようにします。 function makeQueryString(apiName, params) { let queryString = `${apiName}?`; // リクエスト内容分ループ for (const key in params) { // 値のみURLエンコードを行う(文字コードを指定) const value = conv.encode(params[key], encoding); queryString += `${key}=${value}&`; } // 末尾に認証用の値を付与 queryString += `signature=xxx`; return queryString; } 結果は以下のようになりました。 # getUser?name=則巻アラレ&age=13&signature=xxx のURLエンコード結果(Windows-31J) getUser?name=%91%A5%8A%AA%83A%83%89%83%8C&age=13&signature=xxx これで無事に文字コードWindows-31Jの文字列として、サーバ側でデコードができて、 指定ユーザーの情報がAPIのレスポンスで返ってくるようになりましたとさ、めでたしめでたs ......残念ですが、このままではある条件下でエラーになる場合があります。 値だけURLエンコードをしていると、数字の0が消える それは、以下のユーザーで検索を行ったときに起きました...。 // リクエスト内容 const params = { name : '則巻ターボ', age : 0 } # 作成されたクエリストリング getUser?name=%91%A5%8A%AA%83%5E%81%5B%83%7B&age=&signature=xxx おわかりいただけただろうか...。 そう、ageの値が欠けているのだ...\キャー/ ageの値を文字列の'0'とした場合はクエリストリングにage=0&...となりますが、 数字の0であった場合は、age=&...として値が欠けてしまいます。 今回は値が数字の0であった場合は、URLエンコードしないようにしました。 const value = params[key] === 0 ? params[key] : conv.encode(params[key], encoding); # getUser?name=則巻ターボ&age=0&signature=xxx のURLエンコード結果(Windows-31J) getUser?name=%91%A5%8A%AA%83%5E%81%5B%83%7B&age=0&signature=xxx ひとまず、(今回は)ヨシ! というわけで、文字コードを指定して、URLエンコードを行う方法でした。 (今回は本筋から逸れるので記載していませんが、実際は入力値のバリデーションチェックもしています) 利用するAPIの仕様から「=」と「&」をエンコードさせないためにencodeURI()を使用しています。encodeURIComponent()との違いはMDN Web Docsに例として記載があります ↩ 翻訳が若干分かりにくかったので、英語版から引用。ちなみにencodeURIComponent()も同様にUTF-8の文字列として表される。 ↩ iconv-liteのgithub内のwikiにサポートしている文字コードの一覧があります。Windows-31jが!指定!できる! ↩

Viewing all articles
Browse latest Browse all 9050

Latest Images

Trending Articles