4

我一直在这里发疯,试图让 jquery.ajax 与 ie9 一起工作。所以我有一个实现 CORS 的 ASP Web API 2 Rest API。来自所有浏览器的 CORS 请求都有效。IE9 没有工作,因为它使用 XDomainRequest。通过为 IE9 定制 ajaxTransport 实现,我设法让它也能正常工作。

现在 GET 请求似乎工作正常。但是当我从 IE9 发出一个 post 请求时,我收到一个 HTTP 错误 415 - 不支持的媒体类型。

我已将内容类型设置为:“application/json”,并且我也尝试过“application/x-www-form-urlencoded”,但据我了解,XDomainRequest 不支持带有自定义标头的所有内容?有人知道是否需要在 WebAPI 上设置一些特定的东西还是我需要调整请求?

我的请求如下所示:

                        $.ajax({
                        url: hostname + "/api/DDC/Book",
                        type: "POST",

                        contentType: "application/json",
                        data: {
                            DealID: function () {
                                return viewModel.get("DealID");
                            },
                            LocationID: function () {
                                return viewModel.get("LocationID");
                            },
                            Time: function () {
                                return viewModel.get("selectedDateTime.Time");
                            }

                        }
                    })

在服务器上我有这个:

[HttpPost("DDC/Book")]
    [EnableCors(origins: "*", headers: "*", methods: "POST, GET, OPTIONS, PUT, DELETE")]
    public dynamic Post(BookModel model)
    {
       .........

当我在 IE 调试器中分析失败的请求时,这是发出的请求标头:

Key Value
Request POST //api/DDC/Book HTTP/1.1
Accept  */*
Origin  http://myurl.com
Accept-Language hr-HR
Accept-Encoding gzip, deflate
User-Agent  Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host    www.somehost.com
Content-Length  55
DNT 1
Connection  Keep-Alive
Cache-Control   no-cache

我真的在这里失去了所有希望,IE 让我发疯了(该死的微软:D),所以任何帮助或建议都非常受欢迎。

编辑:通过更多研究,我发现 WebAPI 需要一种内容类型才能工作,而 XDomainRequest 不会发出。因此,我看到的唯一解决方案是在未设置任何内容时调整我的 webapi,使其具有默认的内容类型。虽然还不知道怎么做

EDIT2:通过将我所有的 POST 转换为 GET 暂时破解了我的方法,不知道这有多聪明,但我现在看不出有更大的问题,所以在我解决问题之前它会起作用

4

3 回答 3

8

设法自己解决了。正如 Ray Nicholus 所指出的,当没有 Content-Type 时,ASP Web API 默认为“application/octet-stream”Content-Type。我需要默认的“application/x-www-form-urlencoded”。

我设法通过编写自己的简单消息处理程序来实现这一点,该处理程序检查传入的请求“Content-Type”,如果没有任何内容,它会添加一个“application/x-www-form-urlencoded”。

这是代码:

public class DefaultContentTypeMessageHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Content.Headers.ContentType == null)
            request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");


        var response = await base.SendAsync(request, cancellationToken);


        return response;
    }

}

更新:

正如 Robert Christ 在下面的评论中所写,我正在为那些以前没有使用过消息处理程序的人扩展答案:

对于那些乍一看不明白的人,DelegatingHandlers 允许您在请求/响应对象真正触及 WebAPI 框架内部之前对其进行修改。框架中没有其他任何东西可以真正让您在模型绑定之前修改传入的请求,而无需实际编写自定义模型绑定器(呃)。因此,在这里,您可以嗅出 null 内容类型(XDomainRequest 规范中的缺陷保证了这一点),将其更新为 xml 或 json,您将能够正确解析传入的请求。

编写消息处理程序后,您需要将其注册到 WebAPI。您可以在 WebApiConfig 类中执行此操作:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {

        config.MessageHandlers.Add(new DefaultContentTypeMessageHandler());
        // Rest of your code

     }
 }
于 2013-09-24T16:03:10.883 回答
1

只是为了确认您已经在几次更新中编辑了您的问题:是的,XDomainRequest 在请求中不包含 Content-Type 标头。正如您现在可能知道的那样,您无法通过此传输设置任何标头。

对于大多数服务器端框架来说,缺少 Content-Type 尤其成问题,因为这意味着它们将无法自动解析响应的内容。在没有 Content-Type 标头的情况下,RFC 2616 说正文被假定为 application/octet-stream,在这种情况下这可能不是您想要的。因此,在这种情况下,您需要通过硬编码相关请求的预期 Content-Type 来“手动”解析请求正文服务器端。

我强烈建议您不要简单地将所有 POST 转换为 GET。根据 RFC 2616,GET 请求应该是“安全的”。只需将所有 POST 重命名为 GET,您就不再遵循 GET 请求的定义和接受的语义。换句话说,不要这样做。

于 2013-09-24T04:17:48.473 回答
1

上面丹尼斯的回答使用仅在 .NET 4.5 中可用的异步。对于 .NET 4 和可能更低的版本,请改用以下委托处理程序:

 public class DefaultContentTypeMessageHandler : DelegatingHandler
 {
      protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
      {
          if (request.Method == HttpMethod.Post && request.Content.Headers.ContentType == null)
          {
              request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
          }
          return base.SendAsync(request, cancellationToken);
      }
 }

另外,不要忘记您的 USING 语句,您将需要:

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
于 2013-10-03T09:44:07.467 回答