JSONを返却するAPIを作成した際、HTMLを埋め込みたい時のエンコードについて
PHPでAPIを用意してAjaxで呼び出し、divタグのinnerHTMLにそのまま埋め込みたいというのはよくある話。
APIにHTML自体を生成させて吐き出させるということをやると、中途半端にHTMLタグが再生されてグズグズのページが見えてしまうというのもよくある話。
そこで、HTMLなんだけどJSONでラップしてあげて、Ajax側ではデコードと構造チェックで再生判断をしてあげましょうという結果に至りました。
対処案1
PHP側エンコード → htmlspecialchars() Javascript側デコード → 自前で実装
ぐぐったら、Javascript用に置換パターンを載せてくれているサイトがありました。
これはシンプルそうです。
http://phpspot.org/blog/archives/2007/11/javascript_html.html
API側(PHP)
$output = array( 'responses' =>; array( 'output'=>; htmlspecialchars($body), ), );
受け取り側(Javascript)
function htmlspecialchars_decode(ch) { ch = ch.replace(/\&\;/g,"&") ; ch = ch.replace(/\"\;/g,'"') ; ch = ch.replace(/\'\;/g,"'") ; ch = ch.replace(/\<\;/g,"<") ; ch = ch.replace(/\>\;/g,">") ; return ch ; } var req = new XMLHttpRequest(); req.open('GET', url); req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); req.onload = function() { var res = JSON.parse(this.responseText); target.innerHTML = htmlspecialchars_decode(res.responses.output); };
対処案2
PHP側エンコード → rawurlencode() Javascript側デコード → decodeURIComponent()
JSONが長くなりますが、標準的なコンポーネントのみで対応できるのでコードが綺麗になります。
言語をまたぐので、RFC3986の取り決めに従ったモジュールを利用する(PHP側はurlencode()を使わない、Javascript側はdecodeURI()を使わない)というのもポイントになります。
API側(PHP)
$output = array( 'responses' => array( 'output'=> rawurlencode($body), ), );
受け取り側(Javascript)
var req = new XMLHttpRequest(); req.open('GET', url); req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); req.onload = function() { var res = JSON.parse(this.responseText); target.innerHTML = decodeURIComponent(res.responses.output); };
Javascriptにhtmlspecialcharsをエンコード、デコードセットで用意しておくと便利です。 jsのライブラリをいじれる開発なら迷わずこれ追加かな。