web-dev-qa-db-ja.com

ajax経由で投稿を実行すると、JSON結果の代わりにBad Requestが返される

JavaScript

jqXHR = $.ajax({ url: $frm.attr("action"), type: "POST", dataType: "json", cache: false,
  headers: headers, contentType: "application/json;charset=UTF-8", data: ko.mapping.toJSON(data, map),
  beforeSend: function(x) {
    if (x && x.overrideMimeType) {
      return x.overrideMimeType("application/json;charset=UTF-8");
    }
  }
});

jqXHR.fail(function(xhr, err, msg) {  /* xhr.responseText  NEED TO BE JSON!!! */ });

Chromeで

ヘッダー

Request Method:POST
Status Code:400 Bad Request
Request Headersview source
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4
Connection:keep-alive
Content-Length:10
Content-Type:application/json;charset=UTF-8
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payloadview source {Id:0}
Response Headersview source
Cache-Control:private
Content-Length:54
Content-Type:application/json; charset=utf-8
Date:Thu, 27 Feb 2014 14:01:59 GMT
Server:Microsoft-IIS/8.0
X-AspNet-Version:4.0.30319
X-AspNetMvc-Version:5.1
X-Powered-By:ASP.NET

応答

[{"名前": "Nome"、 "ErrorMessage": "campoobrigatório。"}]

Chromeで機能します!


IE8では

ヘッダー(リクエスト)

POST /Motivos/Salvar HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: pt-br
x-requested-with: XMLHttpRequest
Content-Type: application/json;charset=UTF-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)
Content-Length: 10
Connection: Keep-Alive
Pragma: no-cache

Headers(Response)

HTTP/1.1 400 Bad Request
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.0
X-AspNetMvc-Version: 5.1
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 27 Feb 2014 13:51:46 GMT
Content-Length: 11

Bad Request

動作しません!!

Asp.net MVC

フィルタ

public class HandleExceptionAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
        {
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            var ex = filterContext.Exception.GetBaseException();
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    ex.Message,
                    ex.GetType().Name
                }
            };
            filterContext.ExceptionHandled = true;
        }
        else
        {
            base.OnException(filterContext);
        }
    }
}

GlobalFilterCollectionに適用

コントローラ

[ValidateJsonAntiForgeryToken, HttpPost]
public virtual JsonResult Salvar(TViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        TEntity model;
        if (default(TKey).Equals(viewModel.Id))
        {
            model = Mapper.Map<TEntity>(viewModel);
            AdicionarEntidade(model, viewModel);
        }
        else
        {
            model = Repositorio.Get(viewModel.Id);
            Mapper.Map(viewModel, model, typeof(TViewModel), typeof(TEntity));
            SalvarEntidade(model, viewModel);
        }

        return SalvarResult(model);
    }

    Response.StatusCode = 400;
    return Json(ModelState.ToJson(), JsonRequestBehavior.AllowGet);
}

伸び

public static object ToJson(this ModelStateDictionary dic, params string[] othersMessages)
{
    var states = (from e in dic where e.Value.Errors.Count > 0
                  select new { Name = e.Key, e.Value.Errors[0].ErrorMessage }).ToList();

    if (othersMessages != null)
        foreach (var message in othersMessages)
            states.Add(new { Name = "", ErrorMessage = message });

    return states;
}

ご質問

  • Xhr.resposeTextオブジェクトがないのはなぜですか?
  • Chromeで回復するのと同じ方法でJSONを取得するにはどうすればよいですか?

フォームに入力するためにJSONが必要です!

注:2014年3月11日

コントローラーにResponse.TrySkipIisCustomErrors = true;を追加すると機能します。 responseTextはjsonを返します。どうして?

24
ridermansb

これは、コントローラが生成しているエラーメッセージを送信するのではなく、カスタムエラー応答を使用しようとするIISの問題であると考えてください。

<system.webServer>
    ...
    <httpErrors existingResponse="PassThrough"></httpErrors>
    ...
</system.webServer>

または

Response.TrySkipIisCustomErrors = true;

リファレンス- https://stackoverflow.com/a/4029197/1304559

このブログ投稿をチェックしてください http://weblog.west-wind.com/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors

応答コードは400に設定されているため、IISはコンテンツをカスタムエラーページコンテンツに置き換えます

34
aravind

応答はContent-Type: text/html httpヘッダーで返されますが、application/jsonである必要があります。依存しているため、これはChromeの問題ではありません(コンソールに 不一致の警告 が表示されません)。 overrideMimeType ...ご想像のとおり、IEには適していません。実際、次のものは古いバージョンのIEでは実行されません。

if (x && x.overrideMimeType) {
  return x.overrideMimeType("application/json;charset=UTF-8");
}

ソリューションは、コンテンツが正しいコンテンツタイプで提供されるようにすることです。 Burp Suite などの改ざんツールに精通している場合は、正しいヘッダーをオンザフライで追加して、問題が解決するかどうかを確認できます。 AddHeader のようなメソッドのインライン化をおそらく避け、これをより高い位置で修正できる方法があるかどうかを確認します-ルーティング、おそらく-レベル。

2
o.v.

私が目にしている問題は、JSONのエンコーディングをUTF-8に設定しようとしていることです。通常は問題なく動作しますが、IISではUTF-8が不要であることを報告するカスタムエラーが発生します。

他に注意すべきことはほとんどありません。あなたはPOSTを行っているので、サーバーはjsonファイルを期待しています。何も指定しないと、何をすべきかわかりません。

2
jemiloii

役立つはずのフェイルテストを記入しました。

$.post($frm.attr("action"), ko.mapping.toJSON(data, map))
.done(function (dataVal) {
    //process dataVal
    var mystruct = GenerateCache($.parseJSON(dataVal));
})
.fail(function (jqxhr, textStatus, error) {
    if (jqxhr.responseText.indexOf("YourMoniker") != -1) {
        parseData($.parseJSON(jqxhr.responseText));
    } else {
        var err = textStatus + ', ' + error;
        console.log("Request Failed: " + err);
    }
});


function GenerateCache(data) {
    var obj = function () { };
    obj.prototype = data;
    return new obj();
}

特に、.failセクションのエラー処理を確認してください。

1
CaptainBli

IE(IE11を含むすべてのバージョン)は、ステータステキストに「Bad Request」を入れ、メッセージとして入れたJSONを無視します。

エラー時にIEでxhr.responseTextを使用するには、HttpStatusCode.BadRequest;でJsonまたはJsonResultを返す代わりに、例外をスローする必要があります

だから...以前:

Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { Message = "There is already a distribution set which covers part or all of this period" });

これは実際には、Chrome、FF、および正常なブラウザで機能します。後:

throw new Exception("You have posted invalid datas.");

未処理の例外として、それは応答としてブラウザーに渡され、これはChrome、FF、さらにはIEでも機能します。それはすべての未処理の例外(または単に、例外に関しては例外)と同じように、優雅ではありませんが、適切な応答を受け取ることができます。

0
Nomenator

それはあなたのコントローラーではありません、それはうまくいきます。必須フィールドがありません:IEとChromeの両方がステータスコード_400 Bad Request_を返します-ChromeのみがresponseTextを適切に処理し、あなたは_[{"Name":"Nome","ErrorMessage":"campo obrigatório."}]_が欠落しているフォームフィールドがあることを意味します。

全文を検索しましたが、_XMLHttpRequest.responseText_の200以外のステータスコードの処理における特定のIEバグへの参照は見つかりませんでしたが、IEが置き換えられているようです独自のレスポンスボディ:

_Headers (Response)

HTTP/1.1 400 Bad Request
...
Content-Length: 11

Bad Request
_

「コンテンツ」が扱う「コンテンツ」が「Bad Request」ステータステキストであり、適切なjsonレスポンスではないことを示します(たとえば、Chromeはcontent-length 54として読み取ります)。これは、IEが応答の本文を破棄していることを意味している可能性があります(おそらく、信じられないほど、流血です)。 jqXHRオブジェクトの残りの部分とfailハンドラーの引数をダンプして、どこかにあるかどうかを確認してください。

0
Brian North