fetch
で Shift_JIS を扱おうとしたら文字化けしたので、解決方法を書きます。
1. 流れ
-
fetch
で DOM として直接読み込むことはできない - なので、一回 text として読み込んで DOM に parse する
- ところが、
response.text()
で文字コードが UTF-8 以外で文字化けし、解決方法は (おそらく) ない (Content-Type
にcharset
を指定しても効果なし) - なので、一度バイナリデータとして読み込み、文字コードを指定して文字列に変換し、そこから DOM に parse する
参考「JavaScriptのFetch APIで返ってきたものをDOMとして扱う - ひと夏の技術」
参考「fetch APIでUTF8以外のエンコーディングだと辛い – 阿Qさんと一緒」
2. ソースコード
2.1. 方法 1: Response -> Blob -> fileReader.readAsText()
(async () => {
//
const readAsText = (blob, encoding = null) => new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => { resolve(reader.result) };
reader.readAsText(blob, encoding);
});
const parseHTML = html => new DOMParser().parseFromString(html, 'text/html');
//
const url = '...';
const response = await fetch(url);
const blob = await response.blob();
const html = await readAsText(blob, 'shift-jis');
const dom = parseHTML(html);
// 処理
console.log(dom.head);
})();
2.2. 方法 2: Response -> ArrayBuffer -> textDecoder.decode()
TextDecoder
が使用できるブラウザならこちらの方がシンプルに書けます。
※新 Edge は対応していないようです。
参考「TextDecoder - Web API | MDN」
(async () => {
//
const decodeAsText = (arrayBuffer, encoding = null) => new TextDecoder(encoding).decode(arrayBuffer);
const parseHTML = html => new DOMParser().parseFromString(html, 'text/html');
//
const url = '...';
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
const html = decodeAsText(arrayBuffer, 'shift-jis');
const dom = parseHTML(html);
// 処理
console.log(dom.head);
})();