前后端分离之CORS和WebApi

目前的项目是前端mv*+api的方式进行开发的,以前都是没有跨域的方案,前后端人员在同一个解决方案里边进行开发,前端人员要用IIS或VS来开发和调试Api,这样就很不方便,迫切需要跨域访问Api.

评选了很多解决方案最终选择,CORS+WebApi

cors科普:http://www.ruanyifeng.com/blog/2016/04/cors.html

cors网站:http://enable-cors.org/

mvc源码:https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.Cors/CorsMessageHandler.cs

快速入门可以看一些教程,自己要扩展源码是一条捷径.

示例代码:https://github.com/gutun/aspnet/tree/master/cors

1.新建WebApi项目实现CORS跨域

1.1 新建一个新的项目CrossDomain

1.2. 安装 Microsoft.AspNet.WebApi.Cors

Install-Package Microsoft.AspNet.WebApi.Cors

1.3. 配置App_Start目录下的 WebApiConfig文件

Config中要启用 CORS的支持我选择默认的MediaType为json方式。

1.4 新增UserController,在里边新增两个方法,get用来ping,代表url是通的,post模拟真正的数据提交,我们所有的api访问走post, request的入参和出参可以定义通用的实体。这里模拟post提交数据解析成UserInfo的实例。

2.JQuery Ajax跨域

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>
    </head>
    <body>
    <script>
        $.ajax({
            url:'http://localhost:64542/api/user',
            type:'POST',
            data:{"Id":"1","Name":"张三"},
            dataType:'json',
            //Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
            //contentType: 'application/json; charset=utf-8',
            cache: false,
            crossDomain: true,
            success:function(data){
                alert(data);
            }
        });
    </script>
    </body>
</html>

使用Nodejs本地服务器访问WebApi项目,成功的访问到了api/User,状态是200.

3.IE8,IE9支持CORS.

CORS在浏览器的支持情况,IE8和IE9是部分兼容,86%的浏览器是支持的,占了大部分,为了支持IE8和IE9我找到了一个补丁jquery.transport.xdr.min.js 用来弥补在IE8和IE9下的不足。

https://github.com/gfdev/javascript-jquery-transport-xdr.js

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>
        <script src="http://cdn.bootcss.com/jquery/1.11.1/jquery.min.js"></script>
        <!--[if (IE 8)|(IE 9)]>
        <script src="http://cdn.rawgit.com/gfdev/javascript-jquery-transport-xdr/master/dist/jquery.transport.xdr.min.js"></script>
        <![endif]-->
    </head>
    <body>
    <script>
        //http://www.ruanyifeng.com/blog/2016/04/cors.html
        $.ajax({
            url:'http://localhost:64542/api/user',
            type:'POST',
            data:{"Id":"1","Name":"张三"},
            dataType:'json',
            //Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
            //contentType: 'application/json; charset=utf-8',
            cache: false,
            crossDomain: true,
            success:function(data){
                alert(data);
            }
        });
    </script>
    </body>
</html>

喜出往外,跑起来后遇到了,415错误,未识别的Content-Type,这是因为在IE8和IE9下,Content-Type为空造成的。

 

http://stackoverflow.com/questions/18964258/asp-web-api-post-request-with-cors-and-ie9-xdomainrequest-objec

新增DefaultContentTypeMessageHandler用来处理Request 

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Cors;
using System.Web.Http.Cors;

namespace CrossDomain
{
    public class DefaultContentTypeMessageHandler : DelegatingHandler
    {
        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
            if (corsRequestContext != null) //判断是否是跨域的请求
            {
                if (request.Method == HttpMethod.Post && request.Content.Headers.ContentType == null) //ConentType为空,使用默认值
                    request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
            }

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

            return response;
        }

    }
}

再次更改WebApiConfig文件,在MessageHandlers管道中追加刚写的DefaultContentTypeMessageHandler,这样ContentType为空的跨域请求会使用默认的ContentType.

using System.Web.Http;
using System.Web.Http.Cors;

namespace CrossDomain
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //新增CORS支持
            var corsAttr = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(corsAttr);
            //默认使用json格式,移除xml格式
            config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
            //处理Content-Type
            config.MessageHandlers.Add(new DefaultContentTypeMessageHandler());

            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

在chrome,IE8,IE9,IE10+上测试没有问题。

posted @ 2016-10-20 16:31  故土难离  阅读(1240)  评论(0编辑  收藏  举报