25

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."}]

在铬中工作!


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

4

6 回答 6

36

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

于 2014-03-18T11:18:49.750 回答
2

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

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

于 2014-03-13T03:25:42.153 回答
2

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

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

您的解决方案可能是确保以正确的内容类型提供内容。如果您熟悉Burp Suite之类的篡改工具,则可以即时添加正确的标头,看看是否能解决问题。我可能会避免使用内联方法AddHeader,看看是否有一种方法可以将其固定在更高的路由级别,也许是级别。

于 2014-03-18T04:58:19.563 回答
1

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

$.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小节中的错误处理。

于 2014-03-17T22:23:44.713 回答
0

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

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

Headers (Response)

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

Bad Request

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

于 2014-03-17T18:40:13.990 回答
0

IE(所有版本,包括 IE11)将在状态文本中放入“Bad Request”并忽略您作为消息输入的 JSON。

为了在错误时在 IE 中使用 xhr.responseText,您需要抛出异常而不是返回 Json 或 JsonResultHttpStatusCode.BadRequest;

所以...之前:

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

于 2016-04-01T14:57:57.237 回答