以前ちょろっとJavaScript(jQuery)を書いた際にajaxを使用したのですが、
題名の通り、正常にレスポンスが取得できているのにも関わらず、
失敗(fail)として処理されてしまう現象に出くわしました。
その時は軽く調べて暫定的に対応してしまったので、しっかり調べてみました。
備忘の為に記事に残し、同じ現象に悩んでいる人の助けになれば。
現象を確認
$.ajax()を利用する場合、下記のような記述になるかと思います。
今回は例としてRedmineのチケット更新APIを実行します。
$.ajax({
type: 'PUT',
url: '/issues/999.json',
headers: {
'API-Key': API_KEY
},
dataType: 'json',
data: params
contentType: 'application/json',
}).done(function(resp) {
console.log(resp);
}).fail(function(jqXHR, textStatus, errorThrown){
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
});
で、PUT処理がステータスコード=200(成功)で終了すれば、done()に処理が流れるはず。
が、fail()に入ってきてしまうと。
原因
原因は、下記の通り。
jQuery側でレスポンスの内容をJSON形式にパースしようとして、エラーとなっている。
下のキャプチャを見るとわかるかと思います。(”parsererror”としてfail()に入ってきている。)

以下、こちらのjQuery解説サイトから引用させて頂くと、dataType:”json”を指定した場合、
JSONとしてレスポンスを評価し、JavaScriptオブジェクトが返されます。 このJSONデータは厳格な作法によってパースされるため、奇形と判断されたJSONは拒絶され、パースエラーがスローされます。jQuery1.9からは、空のレスポンスも拒絶されるようになったため、 サーバーは代わりに
nullまたは{}を返す必要があります。
との事。
私のRedmineではjQuery1.11.1が適用されておりますので、
空のレスポンスが拒絶されてパースエラーとなっていた、という事のようです。

対応
dataTypeを指定しない ⇒ エラーになる
いくつか同事象について説明しているサイトをみると、
との記載を見つけました。
これは、再び前述のjQuery解説サイトから引用させて頂きますが、
あなたが期待するサーバーから返されるデータの型を指定します。 もし指定されなければ、jQueryはレスポンスのMIME typeを元に推察することを試みます。
によるものと思われます。
が、今回のケースでは解決できませんでした。
これは下記キャプチャの通り、Redmine側のレスポンスヘッダのContent-Typeが
JSON指定されているから。

自動判定によりJSONと判断され、パースしようとしてパースエラーになってしまう
という事のようです。
dataTypeにtextを指定 ⇒ 解決
上記から、パースされなければエラーにならないと考えられる為、
プレーンテキストとして処理されるよう、textを指定すれば解決しました。
![]()
成功ロジックのdone()に入ってきました。
Redmineのチケット更新APIの成功レスポンスは、nullでも{}でもなく、””(空文字列)という事がわかります。
おわりに
なにかモヤモヤしていたので、原因がハッキリして良かった。
プログラマがレベルアップする方法って、こういう躓きを解決する積み重ねなんだろうなと。。。