【问题标题】:When performing post via ajax, Bad Request is returned instead of the JSON result通过 ajax 执行 post 时,返回 Bad Request 而不是 JSON 结果
【发布时间】:2014-03-31 00:59:44
【问题描述】:

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

回应

[{"Name":"Nome","ErrorMessage":"campo obrigató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

标头(响应)

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。 为什么?

【问题讨论】:

  • 如果您在$.ajax 中设置不同的内容类型,最好将 processData 设置为 false。另外,为什么你在 beforeSend 中是overriding mime type?您可以控制服务器上的返回类型。
  • 你能在 IE 和 chrome 上显示 data: ko.mapping.toJSON(data, map) 的值吗?
  • @KerryLiu 即使设置processData: false,也会出现错误。 * 关于beforeSend,这只是一个测试。即使删除了这个事件,这个错误仍然会发生!
  • @LeeGary 数据:在 IE 中 "{"Id":"0"}"在 Chrome 中 "{"Id":"0"}"
  • 只有我,还是您的 Chrome(响应?)标题也显示状态代码 400 Bad Request

标签: jquery ajax internet-explorer-8 jqxhr asp.net-mvc-5.1


【解决方案1】:

认为这是 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 会将您的内容替换为其自定义错误页面内容

【讨论】:

    【解决方案2】:

    我看到的问题是您尝试将 JSON 的编码设置为 UTF-8。通常它工作得很好,但是,在 IIS 上,它有一个自定义错误来报告不需要 UTF-8。

    还有一些需要注意的事项。您正在执行 POST,因此服务器将需要一个 json 文件。如果不提供,它将不知道该怎么做。

    【讨论】:

    • 1.关于 UTF-8 没有意义,因为它适用于 Chrome。我已经尝试删除 UTF-8 并且仍然出现错误!
    • 2.我正在向服务器发送 JSON!
    • 那么您发送的 json 是什么?您只显示响应 json,响应是服务器发送给客户端的内容。此外,您一次只能发送一个 json 文件。因此,如果您同时提交多个表单,则需要将其打包为一个 json 文件。
    【解决方案3】:

    您的回复带有Content-Type: text/html http 标头,但它应该是application/json。这在 Chrome 中不是问题(并且您不会在控制台中获得 mismatch warnings),因为您依赖于 overrideMimeType...,您猜对了,它对 IE 不友好。事实上,在旧版本的 IE 上永远不会执行以下操作:

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

    您的解决方案可能是确保以正确的内容类型提供内容。如果您熟悉 Burp Suite 之类的篡改工具,则可以即时添加正确的标头,看看是否能解决问题。我可能会避免像AddHeader 这样的内联方法,看看是否有办法可以在更高的路由级别上修复它。

    【讨论】:

      【解决方案4】:

      我填写了一个应该有帮助的失败测试。

      $.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部分的错误处理。

      【讨论】:

      • 我使用$.ajax,因为我设置了标题。如何使用$.post 设置标题?
      • 我明白了。如果您要尝试设置自己的标题,这可能是唯一也是最好的方法。
      • 您的标头中有什么特别需要的内容?
      • 您可以发送$.post( url [, data ] [, success(data, textStatus, jqXHR) ] [, dataType ] )之类的数据类型。您还可以将数据添加到 URL 中的查询字符串,例如:/getData.aspx?param1=test&amp;param2=54...。这仍然可以让您发送数据。
      • 看到$.ajax 方法使用method: 'POST' 发送与$.post 完全相同的请求,并且OP 中发送/接收的标头确实表明IE 将其作为@987654330 发送@request,从一种方法更改为另一种方法将得到完全相同相同的结果
      【解决方案5】:

      这不是你的控制器,它工作正常。您缺少必填字段:IE 和 Chrome 都返回状态代码 400 Bad Request - 但只有 Chrome 正确处理 responseText 并为您提供 [{"Name":"Nome","ErrorMessage":"campo obrigatório."}] 意味着您缺少表单字段。

      虽然我已经搜索了所有内容,但在处理具有非 200 状态代码的 XMLHttpRequest.responseText 时没有发现任何对特定 IE 错误的引用,但看起来 IE 正在用自己的响应正文替换您的响应正文:

      Headers (Response)
      
      HTTP/1.1 400 Bad Request
      ...
      Content-Length: 11
      
      Bad Request
      

      表示它处理的“内容”是“错误请求”状态文本,而不是正确的 json 响应(例如,Chrome 将其读取为 content-length 54)。这可能意味着 IE 正在丢弃您的响应正文(我对此表示怀疑,这太不可思议了),或者只是没有“正确”处理。尝试转储 jqXHR 对象的其余部分和 fail 处理程序的参数,看看是否可以在某个地方找到它。

      【讨论】:

        【解决方案6】:

        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 中起作用。它并不优雅,与所有未处理的异常(或只是异常)相同,但它可以让您收到适当的响应。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-03-19
          • 1970-01-01
          • 1970-01-01
          • 2017-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多