iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

レスポンスが文字化けしたのでエンコードについて調べた

はじめに

こんにちは!株式会社iimonでフロントエンドエンジニアをしているかとうです!

本記事はiimonアドベントカレンダー13日目の記事となります!✨

サーバーから送信されたデータがShift_JISエンコードされている場合、そのままだとJavaScriptで扱えないことがありました。

そこで、本記事では以下の内容についてお話しします!

エンコードを理解する

エンコードとは

身近なGoogle検索の例でエンコーディングを理解します🐈

Googleで「ねこ」と検索したときのリクエストURLです

https://www.google.com/search?q=ねこ&oq=ねこ&gs_lcrp=EgZjaHJvbWUqCQgAEEUYOxiABDIJCAAQRRg7GIAEMgYIARBFGDsyDwgCEAAYBBiDARixAxiABDINCAMQABiDARixAxiABDINCAQQABiDARixAxiABDIMCAUQABgEGLEDGIAEMgwIBhAAGAQYsQMYgAQyDAgHEAAYBBixAxiABDIMCAgQABgEGLEDGIAEMg8ICRAAGAQYgwEYsQMYgATSAQk0OTM5ajBqMTWoAgiwAgE&sourceid=chrome&ie=UTF-8

URLの内容が見やすいので、検索した時のURLをPostmanでリクエストを投げてみます。

クエリパラメータとは

クエリパラメータは、リクエストを行うときにWebサーバーに追加情報を提供します。

URLの?以降に続く文字列で、KeyとValueのセットで表され、それぞれのパラメータは、&で結合されます。

Googleの検索クエリに使用した文字列「ねこ」は、キー「q」とペアになっているValueに当たります。

「ねこ」という文字列が「%E3%81%AD%E3%81%93」という半角英数字とパーセント記号の組合せで表されています。

この文字列の変換を、エンコードと言います。今回のURLでのエンコードは、URLエンコードとも言います。

URLエンコードのイメージ

ちなみに、、

Chrome devtoolsのNetWorkでもクエリパラメータを確認することがでいます。エンコードした状態と、デコードした状態のパターンを確認することができます🙆

「view decoded」をクリックした時

「view URL-encoded」をクリックした時

文字コード

文字コードとは、文字や記号などをコンピュータに理解させるために、番号を割り当てた符号のことです。

⭐️ 文字コードで割り当てられた番号のことを、コードポイントといいます!

文字コード規格

ASCII

英数字や一部の記号を表現するための文字コード規格で、0から127までのコードポイントを持っています。例えば、「A」という文字には65のコードポイントが割り当てられています。

Unicode

世界の様々な言語、記号に番号を割り振って定義した文字コードの標準規格です。割り当てられた番号のことをコードポイントといいます。例えば、 「A」という文字には、16進数でU+0041のコードポイントが割り当てられています。

エンコーディング形式

UnicodeUTF-8/UTF-16

  • UTF-8:1から4バイトの可変長で文字コードを表現する
  • UTF-16:2バイト(16ビット)の固定長でコードを表現する

Shift_JIS

主に日本語に使用されるエンコーディング形式で、文字コードは漢字・ひらがな・カタカナ・英数字・一部の記号のコードポイントを持っています。

文字化けの原因

文字列をバイト列としてどのように符号化するか定義されています。エンコーディング形式が異なると、同じコードポイントが異なるバイト列にエンコーディングされ、文字化けしてしまいます。

例えば、UTF-8エンコードしたものをでShift_JISデコードすると、文字化けが起こることがあります。例えば、日本語の文字が含まれている場合などです。

UTF-8エンコードして、Shift_JISでデコードするイメージ

Shift_JISのレスポンスを扱う

困ったこと

取得したShift_JISエンコーディング形式のレスポンスを、以下の方法でテキストデータとして取得した時、文字化けしました、、🥵

const html = response.text()

文字化けの原因は、textメソッドはレスポンスを常にUTF-8としてデコードするからです。

❗️ Shift-JISを考慮してデコードする必要があります。

解決した方法

  1. ArrayBuffer()メソッドを使用して、サーバーからのレスポンスをバイナリデータとして取得します。

     const arrayBuffer = await response.arrayBuffer();
    
  2. TextDecoderを使用して、ArrayBufferをShift-JISエンコーディング形式でデコードし、文字列として取得します。

    これにより、正しい文字エンコーディングでデータを解釈し、文字化けを防ぐことができます。

     const textDecoder = new TextDecoder('shift-jis');
     const html = textDecoder.decode(arrayBuffer);
    
  3. 取得したHTML文字列をDOMオブジェクトに変換します。これでquerySelectorメソッドなどを使用しての処理が可能になります。

     const parser = new DOMParser();
     const doc = parser.parseFromString(str, 'text/html');
     const result = doc.querySelector('.selector').textContent;
    

全体の処理

const textDecoder = new TextDecoder('shift-jis');
const arrayBuffer = await response.arrayBuffer();
const html = textDecoder.decode(arrayBuffer);
const parser = new DOMParser();
const doc = parser.parseFromString(str, 'text/html');
const result = doc.querySelector('.selector').textContent;

JSのエンコードメソッド

JavaScriptでのエンコードメソッドについて、簡単にまとめました❕

encodeURI()

完全なURIエンコードし、UTF-8に置き換えます。

以下の文字列は置き換えられません。(予約文字) A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #

decodeURI()

エンコードされた完全なURIエンコードされていない状態にします。

const uri = "https://example.com/?x=ねこ";
const encoded = encodeURI(uri);

console.log(encoded); // エンコード結果
console.log(decodeURI(encoded)); // デコード結果

出力

https://example.com/?x=%E3%81%AD%E3%81%93
https://example.com/?x=ねこ

encodeURIComponent()

URIを構成する一部の文字列をUTF-8エンコーディングされた文字列に置き換えます。

以下の文字は置き換えられません。(予約文字) A-Z a-z 0-9 - _ . ! ~ * ' ( )

console.log(encodeURIComponent('cat?'));
// "cat%3F"

console.log(encodeURIComponent('ねこ?'));
// "%E3%81%AD%E3%81%93%EF%BC%9F"

encodeURI()との違い

  • 予約文字の種類
  • 対象の文字列(完全なURLかURLを構成する一部の文字列)
const uri = "https://example.com/?x=ねこ";
console.log(encodeURI(uri));
console.log(encodeURIComponent(uri));

出力

https://example.com/?x=%E3%81%AD%E3%81%93
https%3A%2F%2Fexample.com%2F%3Fx%3D%E3%81%AD%E3%81%93

decodeURIComponent()

エンコードされたURIを構成する一部の文字をエンコーディングされていない状態にします。

console.log(decodeURIComponent('cat%3F'));
// "cat?"
console.log(decodeURIComponent('%E3%81%AD%E3%81%93%EF%BC%9F'));
// "ねこ?"

decodeURI()との違い

  • 予約文字の種類
  • 対象の文字列(完全なURLかURLを構成する一部の文字列)

⭐️ encodeURIComponent() decodeURIComponent()は、URLのクエリパラメータに使用される検索キーワードなどのエンコードとデコードに対して使用するのがよさそうです。

最後に

ここまで読んでくださり、ありがとうございます!🎄

現在弊社ではエンジニアを募集しています!

この記事を読んで少しでも興味を持ってくださった方は、ぜひカジュアル面談でお話ししましょう!

iimon採用サイト / Wantedly / Green

明日のアドベントカレンダーの記事はkimuraさんです!楽しみです!✨✨

参考

URLエンコードとは - IT用語辞典

Technical Introduction

Code point (コードポイント) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN

MDN Web Docs

Fetch API や Blob で UTF-8 以外の文字コードを扱う - Qiita