jQuery.ajaxでJSON形式の空のレスポンスはエラー扱いになる

この前ちょっとはまったのでメモ。まさしくこれ。

jQuery Core 1.9 Upgrade Guide | jQuery

Prior to 1.9, an ajax call that expected a return data type of JSON or JSONP would consider a return value of an empty string to be a success case, but return a null to the success handler or promise. As of 1.9, an empty string returned for JSON data is considered to be malformed JSON (because it is); this will now throw an error. Use the error handler to catch such cases.

レスポンスのステータスコードが200であればOKと判断すればいいかな、ボディは空でいいかな(これがあまりよくないのかもしれないけど)と思ったことがあって試していました。ですがdoneコールバックが呼ばれずしばらくはまっていました。

jQuery.ajaxではコンテンツタイプがapplication/jsonでレスポンスが空の場合、不正なJSONデータとして見なされてfailコールバックが呼ばれるようです。

というあたりを確認してみたMVCのサンプルです。

まずはコントローラ。

public class SampleController : Controller {
    // レスポンスのコンテンツタイプは「application/json」でボディは空
    public ActionResult NullJson() {
        return Json(null, JsonRequestBehavior.AllowGet);
    }

    // レスポンスのコンテンツタイプは「application/json」でボディは「{}」
    public ActionResult EmptyJson() {
        return Json(new {}, JsonRequestBehavior.AllowGet);
    }

    // レスポンスのコンテンツタイプヘッダはなしでボディは空
    public ActionResult Empty() {
        return new EmptyResult();
    }
}

ビューからjavascriptでそれぞれのアクションを呼び出します。

<script>
    $(function () {
        $.post("/sample/nulljson").done(function(response) {
            // ここは呼ばれない
            console.log("nulljson: " + response);
        }).fail(function () {
            console.log("nulljson: fail");
        });

        $.post("/sample/emptyjson").done(function (response) {
            // responseは空オブジェクトになる
            console.log("emptyjson: " + response + "(" + $.isEmptyObject(response) + ")");
        });

        $.post("/sample/empty").done(function (response) {
            // responseは空文字になる
            console.log("empty: " + response);
        });
    });
</script>

コンソールの出力は次のようになります。

nulljson: fail
emptyjson: [object Object](true)
empty: 

以上細かすぎなネタですが、またひとつ勉強になりました。