LoginSignup
0
0

More than 3 years have passed since last update.

VisualForce で rerender すると4バイト文字が化ける

Last updated at Posted at 2020-01-23

問題点

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 ボタンを押下すると

before.png
 ↓
after.png

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 ではサロゲートペア使えないっぽい

数値文字参照 &#x20bb7; にすればいけるかな~と思ったけど
状況変わらず 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 内に置かないと動かないので注意

もうちょいきれいな対策したい

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0