HTMLのフォームタグと違って、Ajaxの場合、GET/POSTで送信しても、 Enctypeを自動で設定してくれるわけでは在りません(Safariは設定されます)。でも、それをほったらかしにするのは、HTML 4.xあたりに怒られるん?というあたりが気になったので、少しだけ調べてみました。
とりあえず、先にtest3.htmまで行って出した結論?を書いておきます。
結論は、Ajax通信時には、oj.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8')とかを明示的にセットしないとRFCやW3CのHTML4x違反ぽいですし、そもそもサーバーへ届かないブラウザがあります。
サーバー側からの返信時には、データUTF-8(BOM付き)にできるなら、BOM付きという部分でユニコード判定ができるようですので、サーバー/クライアントともにUTF-8にそろえられる環境ならいける可能性があります(日本の多くのサーバー環境ではまだ難しいかも)。あるいは、サーバー送出時にもUTF-8化したあとにURIエンコードなどして送出し、受信時に、decodeURIComponent(oj.responseText)すると、必ずUTF-8としてJavaScriptが解釈してくれますので、サーバーとクライアント側HTMLの文字コードが何であっても文字化けしなくなります。
もちろん、URIエンコードではデータ量が増えてしまいますので、
この際、返信時は、Safari(とKHTML)だけ行うというのでもOK。あるいは、圧縮送信するとか、、、。また、setRequestHeaderはSafariは無くても良い。あと、注意したいのは、Opera8.01以前では、setRequestHeaderがエラーになるので分岐が必要。
関連
test2.htm :: test1.htmの調査でいくつか問題のあったAjax通信について、送出時にJavaScriptのencodeURIComponent()でURIエンコードしてみてどうなるかを調べました。
test3.htm :: 送出は、test2.htmのままで、サーバー側からの返信時にURIエンコードして送出してみます
参考
PHPとJavaScriptのURIエンコードを比較
HTML 4.0( 日本語訳 )
17.13.3 フォーム・データの処理
HTML 4.01( 日本語訳 )
17.13.3 フォーム・データの処理
enctype = content-type [CI] この属性は、サーバーにフォームを転送するために使われる content typeを特定します( methodの値が"post"の場合)。この属性の初期値は、 "application/x-www-form-urlencoded"です。 "multipart/form-data"値は、 type="file"のある INPUT要素と組で使わなければなりません。
methodが"get"で、 actionがHTTP URIである場合は actionの値を取り、それに`?'を付け、次いで "application/x-www-form-urlencoded" content typeを使ってコード化された フォーム・データ・セットを追加します。そしてリンクをURIにわたします。この過程でフォーム・データはASCIIコードに限定されます。
methodが"post"で actionがHTTP URIの場合は、 action属性を使ってHTTP "post"処理と enctype属性によって特定された 内容タイプに従って作成されたメッセージを伝えます。
[ NG ]と書いてあっても、該当ケースの場合は単にうまくいかないというだけのことであって、ブラウザに責任があるというような話ではありません。
POSTでフォーム送信、enctype属性を省略
| 送信oj | method | form要素のenctype属性 | setRequestHeaderでのContent-Type指定 |
| FORM |
POST |
属性省略 |
なし |
リクエストヘッダに自動セットされ(Content-Type: application/x-www-form-urlencoded)、データはサーバーへ届き、文字化けもしません。WinIEの送出パケットを見たら、URIエンコードされていました。
<form name = "test1"
action = "http://jsgt.org/ajax/ref/test/enctype/header.php"
method = "post">
<input type = "text"
name = "test"
value = "------テスト------">
<input type = "submit"
value = "送信">
</form>
POSTでフォーム送信、enctype = "application/x-www-form-urlencoded"を明示指定
| 送信oj | method | form要素のenctype属性 | setRequestHeaderでのContent-Type指定 |
| FORM |
POST |
application/x-www-form-urlencoded |
なし |
リクエストヘッダにセットされ、データはサーバーへ届き、文字化けもしません。WinIEの送出パケットを見たら、URIエンコードされていました。
<form enctype = "application/x-www-form-urlencoded"
name = "test2"
action = "http://jsgt.org/ajax/ref/test/enctype/header.php"
method = "post">
<input type = "text"
name = "test"
value = "------テスト------">
<input type = "submit"
value = "送信">
</form>
GETでフォーム送信、enctype属性を省略
| 送信oj | method | form要素のenctype属性 | setRequestHeaderでのContent-Type指定 |
| FORM |
GET |
属性省略 |
なし |
リクエストヘッダにセットされませんが、データはサーバーへは届き、文字化けもしません。WinIEの送出パケットを見たら、URIエンコードされていました。
<form name = "test3"
action = "http://jsgt.org/ajax/ref/test/enctype/header.php"
method = "get">
<input type = "text"
name = "test"
value = "------テスト------">
<input type = "submit"
value = "送信">
</form>
ここからAjax送信
<script>
//暫定版Ajax用ライブラリのミニ版
//http://jsgt.org/mt/archives/01/000409.html
////
// XMLHttpRequestオブジェクト生成
//
// @sample oj = createHttpRequest()
// @return XMLHttpRequestオブジェクト
//
function createHttpRequest()
{
if(window.ActiveXObject){
//Win e4,e5,e6用
try {
return new ActiveXObject("Msxml2.XMLHTTP") ;
} catch (e) {
try {
return new ActiveXObject("Microsoft.XMLHTTP") ;
} catch (e2) {
return null ;
}
}
} else if(window.XMLHttpRequest){
//Win Mac Linux m1,f1,o8 Mac s1 Linux k3用
return new XMLHttpRequest() ;
} else {
return null ;
}
}
function sendRequest(data,method,url , encSwt)
{
//XMLHttpRequestオブジェクト生成
var oj = createHttpRequest();
oj.onreadystatechange =function ()
{
if ( oj.readyState == 4 ){
alert(oj.responseText);
}
}
//URI
if(method.toUpperCase() == 'GET') {
url += "?"+data
}
//open メソッド
oj.open(method,url);
//ヘッダapplication/x-www-form-urlencodedセット
if(encSwt == 1)setEnc(oj)
//send メソッド
oj.send(data);
}
function setEnc(oj){
//ヘッダapplication/x-www-form-urlencodedセット
// @see http://www.asahi-net.or.jp/~sd5a-ucd/rec-html401j/interact/forms.html#h-17.13.3
// @see #h-17.3
// ( enctype のデフォルト値は "application/x-www-form-urlencoded")
// h-17.3により、POST/GET問わず設定
// POSTで"multipart/form-data"を指定する必要がある場合はカスタマイズしてください。
//
// このメソッドがWin Opera8.0でエラーになったので分岐(8.01はOK)
var contentTypeUrlenc = 'application/x-www-form-urlencoded; charset=UTF-8';
if(!window.opera){
oj.setRequestHeader('Content-Type',contentTypeUrlenc);
} else {
if((typeof oj.setRequestHeader) == 'function')
oj.setRequestHeader('Content-Type',contentTypeUrlenc);
}
return oj
}
</script>
GETでAjax送信、setRequestHeader()でのenctype属性指定なし
| 送信oj | method | form要素のenctype属性 | setRequestHeaderでのContent-Type指定 |
| XMLHttpRequest |
GET |
属性省略 |
なし |
WinIE、Opera8.02、Firefox1.02は、リクエストヘッダにセットされませんが、データはサーバーへ届き文字化けしません。
[ NG ]Mac Safari1.25は、リクエストヘッダにセットされ、データはサーバーへ届きますが、文字化けします。
WinIEの送出パケットを見たら、URIエンコードはされていませんでした。
<form name = "test4">
<input type = "text"
name = "test"
value = "------テスト------">
<input type = "button"
onclick ="
sendRequest("&test="+this.form.test.value,
'get',
'http://jsgt.org/ajax/ref/test/enctype/header.php')"
value = "送信">
</form>
POSTでAjax送信、setRequestHeader()でのenctype属性指定なし
| 送信oj | method | form要素のenctype属性 | setRequestHeaderでのContent-Type指定 |
| XMLHttpRequest |
POST |
属性省略 |
なし |
[ NG ]WinIE、Opera8.02、Firefox1.02は、リクエストヘッダにセットされず、データはサーバーへ届いていません。
[ NG ]Mac Safari1.25は、リクエストヘッダにセットされ、データはサーバーへ届きますが、文字化けします。
WinIEの送出パケットを見たら、URIエンコードはされていませんでした(データがサーバーへ届いていないように見えたのは、サーバーで処理できていないだけの可能性大)。
<form name = "test5">
<input type = "text"
name = "test"
value = "------テスト------">
<input type = "button"
onclick ="
sendRequest('&test='+this.form.test.value,
'post',
'http://jsgt.org/ajax/ref/test/enctype/header.php')"
value = "送信">
</form>
POSTでAjax送信、setRequestHeader()でのenctype属性指定なし。フォームのenctype属性で指定してみる。
| 送信oj | method | form要素のenctype属性 | setRequestHeaderでのContent-Type指定 |
| XMLHttpRequest |
POST |
application/x-www-form-urlencoded |
なし |
[ NG ]WinIE、Opera8.02、Firefox1.02は、リクエストヘッダにセットされず、データはサーバーへ届いていません。
[ NG ]Mac Safari1.25は、リクエストヘッダにセットされ、データはサーバーへ届きますが、文字化けします。
WinIEの送出パケットを見たら、URIエンコードはされていませんでした(データがサーバーへ届いていないように見えたのは、サーバーで処理できていないだけの可能性大)。
<formform enctype = "application/x-www-form-urlencoded"
name = "test6">
<input type = "text"
name = "test"
value = "------テスト------">
<input type = "button"
onclick ="
sendRequest('&test='+this.form.test.value,
'post',
'http://jsgt.org/ajax/ref/test/enctype/header.php')"
value = "送信">
</form>
POSTでAjax送信、setRequestHeader()でのenctype属性指定あり
| 送信oj | method | form要素のenctype属性 | setRequestHeaderでのContent-Type指定 |
| XMLHttpRequest |
POST |
属性省略 |
application/x-www-form-urlencoded |
WinIE、Opera8.02、Firefox1.02は、リクエストヘッダにセットされ、データはサーバーへ届き文字化けしません。
[ NG ]Mac Safari1.25は、リクエストヘッダにセットされ、データはサーバーへ届きますが、文字化けします。
WinIEの送出パケットを見たら、URIエンコードはされていませんでした。
<form name = "test7">
<input type = "text"
name = "test"
value = "------テスト------">
<input type = "button"
onclick ="
sendRequest('&test='+this.form.test.value,
'post',
'http://jsgt.org/ajax/ref/test/enctype/header.php',1)"
value = "送信">
</form>