問題点
SalesForce の VisualForce で rerender すると
4バイト文字が文字化けする
サンプル
単純にボタン押したら再描画するだけの画面を作成
Test.vfp
<apex:page standardController="User" extensions="TestController" title="Test">
<div>rerender範囲外:𠮷野家</div>
<apex:form id="frm">
<div>rerender範囲内:𠮷野家</div>
<apex:commandButton value="rerender" action="{!act}" status="reloadStatus" rerender="frm" />
</apex:form>
</apex:page>
TestController.apxc
public class TestController {
public TestController(ApexPages.StandardController controller) {
}
public void act(){
return;
}
}
これで rerender
ボタンを押下すると
rerender
範囲内の「𠮷野家
」が「ஷ野家
」になってしまう
※範囲外に関しては変更なし
調査
文字コード
とりあえず「𠮷
」と「ஷ
」のコードポイント調べた
Test.js
console.log('ஷ'.codePointAt().toString(16)); // 0x0bb7
console.log('𠮷'.codePointAt().toString(16)); // 0x20bb7
絶対これや
サロゲートペア文字(4バイト文字)がおかしくなる模様
欠損箇所
rerender
の範囲外は正常なことから apex:commandButton
が怪しい
ボタン押下時は Ajax で Apex にアクセスしてるようなのでレスポンス内容を見てみる
Response
<?xml version="1.0"?>
<html lang="en_US" xmlns="http://www.w3.org/1999/xhtml"><head>
<!--省略-->
</head>
<body>
<form id="j_id0:frm" name="j_id0:frm" method="post" action="https://hogehoge.visual.force.com/apex/Test?core.apexpages.request.devconsole=1" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_id0:frm" value="j_id0:frm" />
<div>rerender範囲内:ஷ野家</div>
<!--省略-->
</body>
</html>
もう化けとる
このへん見る限り XML ではサロゲートペア使えないっぽい
数値文字参照 𠮷
にすればいけるかな~と思ったけど
状況変わらず Ajax のレスポンス時点で文字化けしてた。
対策
苦肉の策としてエスケープを挟むことにした
画面側でデコードできればURLエンコードとか他のでもいいと思う
Test.vfp
<apex:page standardController="User" extensions="TestController" title="Test">
<div>rerender範囲外:𠮷野家</div>
<apex:form id="frm">
<div id="yoshi" style="visibility:hidden;">%uD842%uDFB7</div>
<apex:commandButton value="rerender" action="{!act}" status="reloadStatus" rerender="frm" />
<script>
var ysdiv = document.getElementById('yoshi')
ysdiv.innerHTML = unescape(ysdiv.innerHTML);
ysdiv.style.visibility = "visible";
</script>
</apex:form>
</apex:page>
エスケープ後の文字列を表示してJSで無理矢理元に戻す感じ
<script>
を rerender
内に置かないと動かないので注意
もうちょいきれいな対策したい