none
关于JS跨域通过put方式请求WebApi的问题,实现DelegatingHandler之后,如何得到Action执行的结果,并返回输出到HttpResponseMessage RRS feed

  • 问题

  • 场景如下,Js发起跨域请求调用WebApi,通过JsonP和配置站点的Access-Control-Allow-Origin方式,Js通过get和post调用webapi都没有问题。但是对于put和delete方式的调用,无法得到正确的响应,返回405Not Allowed Methods。查看浏览器请求信息,看到Request Method:OPTIONS。网上搜索资料之后,按照一些帖子的建议,在WebConfig下配置对应的Access-Control信息之后,再试,也还是没有正确请求并得到执行.

    后来看到帖子,有说通过实现DelegatingHandler的方式来处理,经测试这种方式确实可以得到正确的响应,并返回200OK的状态。

    但是这种方式,并没有返回请求的路由对应的Action执行的结果到Response,而只是返回的自定义的response。

    public class CorsMessageHandler : DelegatingHandler { const string Origin = "Origin"; const string AccessControlRequestMethod = "Access-Control-Request-Method"; const string AccessControlRequestHeaders = "Access-Control-Request-Headers"; const string AccessControlAllowOrigin = "Access-Control-Allow-Origin"; const string AccessControlAllowMethods = "Access-Control-Allow-Methods"; const string AccessControlAllowHeaders = "Access-Control-Allow-Headers"; protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { bool isCorsRequest = request.Headers.Contains(Origin); bool isPreflightRequest = request.Method == HttpMethod.Options; if (isCorsRequest) { if (isPreflightRequest) { return Task.Factory.StartNew<HttpResponseMessage>(() => { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First()); string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault(); if (accessControlRequestMethod != null) { response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod); } string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders)); if (!string.IsNullOrEmpty(requestedHeaders)) { response.Headers.Add(AccessControlAllowHeaders, requestedHeaders); } return response;//这里返回的response,除了header部分有内容,content里面没有任何的返回。如何得到Put类型的Action执行的结果 }, cancellationToken); } else { return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>(t => { HttpResponseMessage resp = t.Result; resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First()); return resp; }); } } else { return base.SendAsync(request, cancellationToken); } } }

    查看浏览器下的状态如下:

    1. Request URL:
      http://localhost:92/api/comment/100000003?deviceid=134134134134&devicetype=iphone134
    2. Request Method:
      OPTIONS
    3. Status Code:
      <label class="resource-status-image" is="dt-icon-label" style="min-width:0px;min-height:0px;box-sizing:border-box;flex:0 0 auto;">
      </label>
      200 OK
    4. Remote Address:
      [::1]:92

    Response Headers:

    1. Access-Control-Allow-Methods:
      PUT
    2. Access-Control-Allow-Origin:
      *
    3. Access-Control-Allow-Origin:
      http://localhost:58780
    4. Cache-Control:
      no-cache
    5. Content-Length:
      0
    6. Date:
      Fri, 17 Mar 2017 01:22:46 GMT
    7. Expires:
      -1
    8. Pragma:
      no-cache
    9. Server:
      Microsoft-IIS/10.0
    10. X-AspNet-Version:
      4.0.30319
    11. X-Powered-By:
      ASP.NET

    Request Headers:

    1. Accept:
      */*
    2. Accept-Encoding:
      gzip, deflate, sdch, br
    3. Accept-Language:
      zh-CN,zh;q=0.8
    4. Access-Control-Request-Headers:
    5. Access-Control-Request-Method:
      PUT
    6. Cache-Control:
      no-cache
    7. Connection:
      keep-alive
    8. Host:
      localhost:92
    9. Origin:
      http://localhost:58780
    10. Pragma:
      no-cache
    11. Referer:
      http://localhost:58780/Feature/Yiyuzheng

    在CorsMessageHandler的SendAsync里,自定义输出Response.Content之后,可以在浏览器得到返回。

    response.Content = new StringContent("OK");
    但是问题是,跨域请求的地址指向的是一个Action,我如何得到Action执行之后的消息体呢?



    2017年3月17日 1:42

全部回复

  • 这几天看了webapi框架揭秘,最后面的章节讲到了如何实现跨域资源共享,回顾上次的测试案例,是因为没有得到预检请求之后的第二次请求。

    2017年3月30日 3:22
  • 如果是非简单请求,浏览器会先发出一次预检请求,响应成功之后,再得到一次请求
    2017年3月30日 3:24