前置き
はいどうも、たねだです。
最近野暮用でまともにjavascriptを触ったこともないのに
ノリで使えると信じてElectronを使用しています。
構造としてはElectron(index.html)にある入力フィールドへ文字列を入力して送信ボタンを押すと
そのデータを取得してPython(FastAPI)に渡すというシンプルな仕組みです。
ところが、何度やっても受け取った値がコンソール上でのみ文字化けしてしまい困ったという話。
このコンソール上でのみ文字化けしていたというのが
今回の問題の最大のポイントでしたので
同じような悩みで右往左往している方のヒントになれば幸いです。
ではやっていきましょう!
環境
- Windows11 24H2
- VSCode 1.95.1
- npm 10.9.0
- node v22.11.0
試したこと
当然ですが問題が生じてからは
送受信する文字列が関わる処理に片っ端からconsole.log()
をおいて確認しました。
コードを全て載せると煩雑になるので
ひとまず重要っぽいところだけ載せて進めていきます。
document.getElementById('sendButton').addEventListener('click', async () => {
const message = document.getElementById('inputField').value;
const response = await window.electronAPI.sendData(message);
document.getElementById('responseField').innerText = `Response from Python: ${response}`;
});
まずは、index.html
にある送信ボタンを押したときの動作です。
sendButtonがクリックされるとipcMainにvalueを渡します。
そして後述のmain.js
にデータが渡り、そこからさらにPythonサーバーへ送られた後
なんやかんやあってindex.html
のresponseFieldに
Response from Python: ${response}
が表示されるというわけですね。
このとき、確認したいのはmessageとresponseがどうなっているかです。
この時点で文字化けないし何かおかしなことになっている場合は
そもそもindex.html
からの受け渡しに失敗している可能性があります。
今回は該当しなかったので
renderer.js
およびindex.html
は問題なさそうとひとまず判断。
// ~その他の記述
// Renderer.jsからデータを受け取って、Pythonサーバーに送信するコード
ipcMain.handle('send-data', async (event, message) => {
const encodedMessage = encodeURIComponent(message);
const response = await fetch(`http://127.0.0.1:8000/receive-data?message=${encodedMessage}`);
const data = await response.json();
console.log(`Response: ${data.response}`);
return data.response;
});
続いてmain.js
です。
こちらでまずsend-data
から受け取ったmessageが
果たして問題ないのか確認したいところですね。
…すると今回はまずここで文字化けしていることがわかりました。
ここから長らく沼にはまるのですが、
Pythonサーバーにはこの後のencodedMessage
をもって処理を行うので
Pyhtonの問題でもないだろうと考えました。
(というかそもそもターミナルをnpmで立ち上げているのでPythonからのログは直接出ない)
エンコードやデコードをrenderer.js
とmain.js
にかませて
確認してみるも効果なし…。
ここまでで、ipcMainでの文字列の受け渡しがなんかうまいこといっていないのだろう。
つまり問題はmain.js
にあると考えていました。
ところが文字化けしているはずのencodedMessage
ですが、
Pythonサーバーを経由したのちにrenderer.js
によって
responseField
に表示されているのに文字化けしていない…。
念のためPythonサーバーからrenderer.js
へ返される前に
tikinterを立ち上げてラベルとして送られてきた文字列を表示させてみると
やはり文字化けしていない…!
ということでいよいよコンソール上でのみ
文字化けが発生しているという判断に至ったわけですが、ここからも長かった。
これも色々やりましたがほぼ全てが徒労に終わりましたので
一瞬希望が見えた方法だけ1つ残しておきます。
ターミナル上(cmdでもPowerShellでも)にて
chcp 65001
を実行するという方法ですね。
詳しいことはよくわかりませんが
コンソールのエンコーディングを65001(utf-8)にするというコマンドです。
実は上記はまだmain.js
が問題だと思っていた時に試してダメだったので
「やっぱりmain.js
に問題があるんだ」
という執着心が高まり解決に時間がかかったような気がします。
皆さんがこの記事をどういう経緯で見ているのかわかりませんが、
もしかすると上記で直る方もいるかもしれないですね。
そして解決へ…
長々と戦ってきたこの問題もいよいよ終着点です。
まだこの問題に悩んでいるそこのあなた、
とりあえず下記をターミナルで実行してください。
[Console]::OutputEncoding
上記を実行すると、こんな感じの内容が出力されるはずです。
BodyName : utf-8
EncodingName : Unicode (UTF-8)
HeaderName : utf-8
WebName : utf-8
WindowsCodePage : 1200
IsBrowserDisplay : True
IsBrowserSave : True
IsMailNewsDisplay : True
IsMailNewsSave : True
IsSingleByte : False
EncoderFallback : System.Text.EncoderReplacementFallback
DecoderFallback : System.Text.DecoderReplacementFallback
IsReadOnly : False
CodePage : 65001
上記はすでに設定済みのものですが、
ここでutf-8
以外のものが表示された場合
以下を実行してください。
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
実行したら、ターミナルを再起動して再度文字化けしないかを確認してください。
私はここまででひとまず解決しました。
ただ上記では暫定対応になってしまうので、
恒久的に設定を適応する場合は
echo '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8' >> $PROFILE
上記を実行してPROFILE
に直接設定を追加します。
同じくVSCodeの再起動を行い、[Console]::OutputEncoding
で再度
エンコードがutf-8
になっているかを確認して下さい。
もしもうまくいかない場合はecho $PROFILE
を実行して、
$PROFILE
ファイルの位置を確認します。
ない場合はMicrosoft.PowerShell_profile.ps1
を、
C:\Users\YourName\Documents\PowerShell\
の直下に作成した上で
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
を記述し
PowerShellを再起動することで解消される可能性があります。
補足
上記を行うにあたりファイルの実行ができないなどのエラーが出た場合は
ポリシーが関係している場合があります。
Get-ExecutionPolicy
ターミナルで上記を実行してステータスがRestricted
になっている場合は
スクリプトの実行が制限されていますので、
ローカル上のスクリプトを実行可能にするため管理者権限でPowerShellを開き、
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
上記を実行することでポリシーの変更ができます。
その後再度ターミナルを再起動して[Console]::OutputEncoding
にて
エンコーディングがutf-8
になっていれば成功です。
説明するまでもないとは思いますが、
今回変更したポリシーの説明は割愛させていただきますので
詳細を知りたい方は以下MicroSoftが公開している
実行ポリシーについての記事をご覧ください。
以上、お疲れさまでした!