iOS(アプリ)+ajaxでDataCloneError
Webやアンドロイド(アプリ)では問題なかったけどiOS(アプリ)のみで「DataCloneError: The object could not be cloned.」が出てくる
作成日:2020-05-18, 更新日:2020-05-21
元ソースと対応
・HTML側にformタグは無い(※Javascriptで送りたいデータを準備する)
| 元 | 対応後 |
|---|---|
// 送りたいデータを都度、作成
var fd = new FormData();
fd.append('hoge01', xx1);
fd.append('hoge02', xx2);
fd.append('hoge03', xx3);
$.ajax({
url: xxxxxxxxxxxx,
data: fd,
type: 'POST',
dataType: 'json',
contentType: false,
processData: false,
}).done(function(data) {
~以下、略~
|
// 送りたいデータを都度、作成
$('#ID_xxxx').remove();
var _ipt = {
hoge01: xx1,
hoge02: xx2,
hoge03: xx3
};
var _form = document.createElement("form");
for (var i in _ipt) {
var _tmpInput = document.createElement("input");
_tmpInput.setAttribute("name", i);
_tmpInput.setAttribute("type", "text");
_tmpInput.setAttribute("value", _ipt[i]);
_form.appendChild(_tmpInput);
}
_form.id = "ID_xxxx";
_form.style = "overflow:hidden;width:0;height:0;";
document.body.appendChild(_form);
var fd = $('#ID_xxxx').serialize();
$.ajax({
url: xxxxxxxxxxxx,
data: fd,
type: 'POST',
dataType: 'json',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
processData: false,
}).done(function(data) {
~以下、略~
※serialize()を使うためにわざわざformタグを作っている |
・元データは、「FormData()」を「contentType:false」で送る
・変更後は、「serialize()」したデータを「contentType:'application/x-www-form-urlencoded; charset=UTF-8'」で送る
めも
- 「FormData()」が使えない(IE8、IE9以外にも最新のiOSアプリだと使えないってコトかな?)
- 「serialize()」+「POST」で送るなら「contentType:'application/x-www-form-urlencoded; charset=UTF-8'」にする必要があるっぽい
※「FormData()」のときは「contentType:false」
serialize()
「serialize()」はformタグの中身を「hoge01=xx1&hoge02=xx2&hoge03=xx3」という文字列に変換してくれる関数。
※対象は、name属性があるヤツだけ
エスケープ処理をしてやるならわざわざ「serialize()」を使わなくてもいいはず。
経緯
・もともとWEBがあって、ajaxを使ってゴニョゴニョしていた
・そのWEBをアプリで表示するようにした(他人が作業:詳細不明)
・アプリのバージョンアップに伴いiOS(アプリ)でエラーになる
→「修正が必要です」と言われた
状況
・PCでWEBを確認→問題なし
・アンドロイドからWEBを確認→問題なし
・アンドロイド(アプリ)で確認→問題なし
・iOSからWEBを確認→問題なし
・iOS(アプリ)で確認→エラー
サーバ側(PHP)
サーバ側(PHP)・・・エラー以前にそもそもアクセスされていない
・・・ajax(Javascript)側でエラーがあると推測
ajax(Javascript)側の問題
iOS(アプリ)のみ値がクリア or 別の内容に書き換えられている・・・等
リクエストURLの問題
まず、ajaxで使うリクエストURLの問題
→URLがクリアされている or 書換えられている等の問題は無し
フォームデータの問題
「$(xxx).〇〇〇」みたいなトコで取得失敗している可能性
→どこもエラーになっていないっぽい
ajax自体の問題
▼こんなエラーが出ていた
DataCloneError: The object could not be cloned.
渡す値がおかしいってコトなんだろうけど・・・調べると「new FormData()」ってトコがダメと言う人たちが多いっぽい
※ただ、古い情報ばっかり・・・
調査
「new FormData()」がダメってコトで別の方法を調べた。
※色々調べながらしていたので、そもそもダメって内容も含まれる
▼元はこんな感じ
var fd = new FormData();
fd.append('hoge', 'xxx');
fd.append('foo', 'xxx');
fd.append('bar', 'xxx');
$.ajax({
url: xxxxxxxxxxxx,
data: fd,
type: 'POST',
dataType: 'json',
contentType: false,
processData: false,
~ 以下、略 ~
});
オブジェクトでそのまま送る
var fd = {
hoge: 'xxx',
foo: 'xxx',
bar: 'xxx'
};
→サーバ側にデータが送られていない
オブジェクトをserialize()化
var ipt = {
hoge: 'xxx',
foo: 'xxx',
bar: 'xxx'
};
var fd = ipt.serialize();
→formじゃないとダメ。
serialize()の結果を送る
serialize()の結果って「hoge01=xx1&hoge02=xx2&hoge03=xx3」のはずだから、直接、セット。
var fd = 'hoge01=xx1&hoge02=xx2&hoge03=xx3';
→サーバ側にデータが送られていない
serialize()してから送る
面倒だけど、いったんformを作成してやる。その後、作成したformをserialize()・・・という流れ
var _ipt = {
hoge01: xx1,
hoge02: xx2,
hoge03: xx3
};
var _form = document.createElement("form");
for (var i in _ipt) {
var _tmpInput = document.createElement("input");
_tmpInput.setAttribute("name", i);
_tmpInput.setAttribute("type", "text");
_tmpInput.setAttribute("value", _ipt[i]);
_form.appendChild(_tmpInput);
}
_form.id = "ID_xxxx";
_form.style = "overflow:hidden;width:0;height:0;";
document.body.appendChild(_form);
var fd = $('#ID_xxxx').serialize();
→サーバ側にデータが送られていない
GET送信
GETで送る気は無いが、GETで送れるか確認だけしておく。
$.ajax({
~ 略 ~
type: 'GET',
~ 以下、略 ~
});
→サーバ側にデータは送られる
serialize()してJSONでおくる
var fd = $('#ID_xxxx').serialize();
$.ajax({
~ 略 ~
data: JSON.stringify(fd),
type: 'POST',
~ 以下、略 ~
});
→サーバ側にデータが送られていない
・・・そもそもJSONにする必要が無いから・・・
serialize()+contentTypeの設定
「contentType:false」が気になったので変更してみた。
var _ipt = {
hoge01: xx1,
hoge02: xx2,
hoge03: xx3
};
var _form = document.createElement("form");
for (var i in _ipt) {
var _tmpInput = document.createElement("input");
_tmpInput.setAttribute("name", i);
_tmpInput.setAttribute("type", "text");
_tmpInput.setAttribute("value", _ipt[i]);
_form.appendChild(_tmpInput);
}
_form.id = "ID_xxxx";
_form.style = "overflow:hidden;width:0;height:0;";
document.body.appendChild(_form);
var fd = $('#ID_xxxx').serialize();
$.ajax({
~ 略 ~
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
~ 以下、略 ~
});
→データが送れた
値を直で指定
試してはいないけど、下記のような感じでもいけるはず
var fd = 'hoge01=xx1&hoge02=xx2&hoge03=xx3';
$.ajax({
~ 略 ~
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
~ 以下、略 ~
});
この場合、エスケープ処理をしっかりしてあげる必要がある
→面倒そうなので、未調査
追記
2018年あたりの情報で「iOS+FormData()」で似たようなエラーが出ていたらしい。
この時の原因は、formに「input type=file」があって「値が空」のときに出るiOSのSafariのバグだそうだ。
→「値が空のとき、FormData()に含めない」という感じにしてやれば解決したそうだ。
私の場合は・・・・ファイルは無い。
念のために「value」が空の要素を「FormData()」に含めないようにしてみたが、エラーだった。
2020-05-21
useragentを確認してみた。
・「Win+Chrome」 - Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
・「iOS+ブラウザ」 - Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.2 Mobile/15E148 Safari/604.1
・「iOS+アプリ」 - Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) XXXXXXXXXX (iPhone7,2; iOS 12.4.6)
「XXXXXXXXXX」としているトコはカスタムのuseragent。
とりあえずSafariは関係ないっぽい。
・・・ってことは、iOSの問題 or アプリを作ったヤツが問題・・・どっちなんだろう?