When performing post via ajax, Bad Request is retu

2020-02-17 08:14发布

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!!! */ });

In Chrome

Headers

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

Response

[{"Name":"Nome","ErrorMessage":"campo obrigatório."}]

Works in chrome!


In IE8

Headers (Request)

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

NOT WORK!!

Asp.net MVC

Filter

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);
        }
    }
}

Apply on GlobalFilterCollection

Controller

[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);
}

Extenssion

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;
}

Questions

  • Why not have the xhr.resposeText object?
  • How to retrieve JSON in the same way that I recover in Chrome?

I need the JSON to populate the form!

Notes: 03/11/2014

When I add Response.TrySkipIisCustomErrors = true; in my controler, it works! responseText returns the json. Why?

6条回答
Juvenile、少年°
2楼-- · 2020-02-17 08:47

Think this is an issue with IIS trying to use custom error response rather sending the error message that the controller is generating.

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

Or

Response.TrySkipIisCustomErrors = true;

Reference - https://stackoverflow.com/a/4029197/1304559

Check out this blog post http://weblog.west-wind.com/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors

Since response code is set to 400, IIS replaces your content with its custom error page content

查看更多
【Aperson】
3楼-- · 2020-02-17 08:51

I have filled in a fail test that should help.

$.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();
}

Specifically look at the error handling in the .fail section.

查看更多
不美不萌又怎样
4楼-- · 2020-02-17 08:54

Your response comes back with Content-Type: text/html http header, but it should be application/json. This is not an issue in Chrome (and you don't get mismatch warnings in the console) because you're relying on overrideMimeType... which, you guessed it, is not IE-friendly. In fact, the following is never executed on older versions of IE:

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

Your solution could be to make sure the content is served with correct content type. If you're familiar with tampering tools like Burp Suite, you could add the correct header on-the-fly and see if that fixes the problem. I would probably avoid inlining methods like AddHeader and see if there is a way this can be fixed at a higher - routing, perhaps - level.

查看更多
做个烂人
5楼-- · 2020-02-17 09:03

IE (all versions, including IE11) will put "Bad Request" in the status text and ignore the JSON you put in as the message.

In order to use the xhr.responseText in IE on error, you need to throw an exception instead of returning a Json or JsonResult with HttpStatusCode.BadRequest;

So... before:

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

This works in Chrome, FF and any sane browser, really. After:

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

As an unhandled exception, it will be passed to the browser as a response, this will work in Chrome, FF and even in IE. It is not graceful, same as all unhandled exceptions (or just exceptions, for that matter), but it will do the job of letting you receive an appropriate response.

查看更多
做自己的国王
6楼-- · 2020-02-17 09:04

It's not your controller, that's working fine. You're missing a required field: both IE and Chrome are returning status code 400 Bad Request - but only Chrome is properly processing the responseText and giving you [{"Name":"Nome","ErrorMessage":"campo obrigatório."}] meaning you have a missing form field.

Although I've searched all over and haven't found any reference to specific IE bugs in processing XMLHttpRequest.responseText with non-200 status codes, it looks like IE is replacing your response body with its own:

Headers (Response)

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

Bad Request

Indicates that the "content" as it treats it is the "Bad Request" status text, not the proper json response (which Chrome reads as content-length 54, for instance). This might mean IE is discarding your response body (I doubt it, that'd be bloody incredible) or it just isn't be processed "properly." Try dumping the rest of your jqXHR object and the arguments for your fail handler to see if you can find it in there somewhere.

查看更多
Melony?
7楼-- · 2020-02-17 09:06

The issue I am seeing is that your trying to set the encoding of the JSON to UTF-8. Normally it works just fine, however, on IIS, it has a custom error to report that the UTF-8 is not necessary.

Few other things to note. You are doing a POST, so the server will be expecting a json file. If provided none, it will not know what to do.

查看更多
登录 后发表回答