Web API(七):Web API跨域问题

一、什么是跨域问题

跨域:指的是浏览器不能执行其他网站的脚本。是由浏览器的同源策略造成的,是浏览器施加的安全限制。(服务端可以正常接收浏览器发生的请求,也可以正常返回,但是由于浏览器的安全策略,浏览器不能处理服务端的返回)。

那么什么是同源策略呢?

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

正是由于这个原因,如果是在不同的项目之间进行调用(这里说的调用指的是浏览器调用后端,如果是后端直接调用就不会存在跨域问题)就会被浏览器阻止。WebApi中常见的场景:Web Api作为单独的数据服务层,提供接口供前端界面调用,MVC项目作为显示层,这种情况下如果在MVC的前端界面里面通过ajax调用WebApi的接口,就会存在跨域问题。

二、如何解决跨域问题

网上有很多跨域问题的解决方案,这里就不在一一列举了,下面主要讲解一下在WebApi中如何使用CORS解决跨域问题。CORS全称Cross-Origin Resource Sharing,中文全称是跨域资源共享。CORS解决跨域问题的原理是在http的请求报文和响应报文里面加入响应的标识告诉浏览器能够访问哪些域名的请求。

三、使用代码解决跨域问题

下面结合一个具体的实例来讲解在WebApi里面如何使用CORS解决跨域问题。

1、场景描述

新建两个单独的项目:一个WebApi项目(带有MVC功能,用来提供数据和页面显示),一个MVC项目(只是负责页面显示),项目结构如下图所示:

其中,WebApi项目的端口号是:33982,MVC项目的端口号是:34352(这两个端口号是在本机的地址,在其他电脑上端口号可能不同)。显而易见:两个项目的端口号不同,不属于同源,如果在MVC里面通过前端调用WebApi提供的数据接口,就会出现跨域的问题。

2、项目结构

2.1 WebApi项目结构

新建WebApiController文件夹,用来存放WebApi控制器,并新建一个WebApi控制器,命名为Student。StudentController控制器的代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Net;
 5 using System.Net.Http;
 6 using System.Web.Http;
 7 using WebApi.Entity;
 8
 9 namespace WebApi.WebApiController
10 {
11     public class StudentController : ApiController
12     {
13         public static List<Student> studentList = InitStudentList();
14
15         private static List<Student> InitStudentList()
16         {
17             return new List<Student>()
18             {
19                new Student {StudentID =1,StudentName="唐僧",Age=24,Sex="男",Major="师范"},
20                new Student {StudentID =2,StudentName="孙悟空",Age=579,Sex="男",Major="管理"},
21                new Student {StudentID =3,StudentName="沙悟净",Age=879,Sex="男",Major="水利工程"},
22                new Student {StudentID =4,StudentName="白骨精",Age=456,Sex="女",Major="表演"},
23                new Student {StudentID =5,StudentName="玉兔精",Age=456,Sex="女",Major="舞蹈"}
24             };
25         }
26
27         [HttpGet]
28         public IHttpActionResult GetAllStudent()
29         {
30             return Json<List<Student>>(studentList);
31         }
32     }
33 }

修改WebApi配置文件类,路由规则里面增加action,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();

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

新建一个MVC控制器,命名为Student,并添加Index视图,Index视图代码如下:

 1 @{
 2     Layout = null;
 3 }
 4
 5 <!DOCTYPE html>
 6
 7 <html>
 8 <head>
 9     <meta name="viewport" content="width=device-width" />
10     <title>测试跨域问题</title>
11     <script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
12 </head>
13 <body>
14     <div style="background-color:#008000;padding:10px;margin:5px;">
15         <div style="font-weight:bold;margin-bottom:5px;">Get Student List</div>
16         <div style="padding-bottom:5px;">
17             <input id="btnGetStudentList" name="btnGetStudentList" type="button" value="Get Student List" />
18         </div>
19         <div id="students"></div>
20     </div>
21     <script>
22         $(‘#btnGetStudentList‘).click(function () {
23             $.ajax({
24                 url: ‘/api/Student/GetAllStudent‘,
25                 type: ‘GET‘,
26                 dataType: ‘json‘
27             }).success(function (result) {
28                 DisplayStudentList(result);
29             }).error(function (data) {
30                 alert(data);
31             });
32         });
33         function DisplayStudentList(result) {
34             var studentTable = $("<table cellpadding=‘3‘ cellspacing=‘3‘></table>");
35             var studentTableTitle = $("<tr><th>StudentID</th><th>StudentName</th><th>Age</th><th>Sex</th><th>Major</th></tr>");
36             studentTableTitle.appendTo(studentTable);
37
38             for (var i = 0; i < result.length; i++) {
39                 var studentTableContent = $("<tr><td>"
40                     + result[i].StudentID + "</td><td>"
41                     + result[i].StudentName + "</td><td>"
42                     + result[i].Age + "</td><td>"
43                     + result[i].Sex + "</td><td>"
44                     + result[i].Major + "</td></tr>"
45                 );
46                 studentTableContent.appendTo(studentTable);
47             }
48
49             $(‘#students‘).html(studentTable);
50         }
51     </script>
52 </body>
53 </html>

2.2 MVC项目结构

MVC项目结构比较简单,新建一个名为Student的控制器,并添加视图,视图如下:

 1 @{
 2     Layout = null;
 3 }
 4
 5 <!DOCTYPE html>
 6
 7 <html>
 8 <head>
 9     <meta name="viewport" content="width=device-width" />
10     <title>测试跨域问题</title>
11     <script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
12 </head>
13 <body>
14     <div style="background-color:#008000;padding:10px;margin:5px;">
15         <div style="font-weight:bold;margin-bottom:5px;">Get Student List</div>
16         <div style="padding-bottom:5px;">
17             <input id="btnGetStudentList" name="btnGetStudentList" type="button" value="Get Student List" />
18         </div>
19         <div id="students"></div>
20     </div>
21     <script>
23         $(‘#btnGetStudentList‘).click(function () {
24             $.ajax({
25                 url: ‘http://localhost:33982//api/Student/GetAllStudent‘,
26                 type: ‘GET‘,
27                 dataType: ‘json‘
28             }).success(function (result) {
29                 DisplayStudentList(result);
30             }).error(function (data) {
31                 alert("失败");
32             });
33         });
34         function DisplayStudentList(result) {
35             var studentTable = $("<table cellpadding=‘3‘ cellspacing=‘3‘></table>");
36             var studentTableTitle = $("<tr><th>StudentID</th><th>StudentName</th><th>Age</th><th>Sex</th><th>Major</th></tr>");
37             studentTableTitle.appendTo(studentTable);
38
39             for (var i = 0; i < result.length; i++) {
40                 var studentTableContent = $("<tr><td>"
41                     + result[i].StudentID + "</td><td>"
42                     + result[i].StudentName + "</td><td>"
43                     + result[i].Age + "</td><td>"
44                     + result[i].Sex + "</td><td>"
45                     + result[i].Major + "</td></tr>"
46                 );
47                 studentTableContent.appendTo(studentTable);
48             }
49
50             $(‘#students‘).html(studentTable);
51         }
52     </script>
53 </body>
54 </html>

四、测试

1、在不做任何处理情况下的测试

先看看同源下的访问情况,直接启动WebApi项目,截图如下:

点击按钮,测试结果如下:

因为是在同一个域中,所以访问没有问题,前端可以正常获取到WebApi返回的数据。下面在来看看在MVC项目中的测试情况。测试截图如下:

从图中可以看出访问失败了,按F12查看访问情况:

从上面的截图中可以看出,发生了跨域访问,浏览器出于安全性的考虑,不能接收返回的数据。

五、使用CORS解决跨域问题

1、安装CORS

在WebApi项目上右键->管理NuGet程序包,然后搜索“microsoft.aspnet.webapi.cors”,选择第一个进行安装

具体的安装过程在这里不再详细解释。

2、配置跨域

在WebApiConfig.cs类中配置跨域,修改后的代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web.Http;
 5 using System.Web.Http.Cors;
 6
 7 namespace WebApi
 8 {
 9     public static class WebApiConfig
10     {
11         public static void Register(HttpConfiguration config)
12         {
13             // 跨域配置
14             config.EnableCors(new EnableCorsAttribute("*","*","*"));
15
16             // Web API 路由
17             config.MapHttpAttributeRoutes();
18
19             config.Routes.MapHttpRoute(
20                 name: "DefaultApi",
21                 routeTemplate: "api/{controller}/{action}/{id}",
22                 defaults: new { id = RouteParameter.Optional }
23             );
24         }
25     }
26 }

这里使用“*”号表示对所有的域名都可以跨域。再次从MVC里面访问WebApi,查看测试结果:

从上面的截图中可以看出,这时就可以允许跨域访问了,在Response Headers里面添加了:Access-Control-Allow-Origin:*。

六、CORS参数详解

在上面我们在WebApi的配置文件中使用了:

config.EnableCors(new EnableCorsAttribute("*","*","*"));

这一句代码解决了跨域问题。但是这种“*”号是不安全的。查看MSDN,发现EnableCorsAttribute类有如下的构造函数:

public EnableCorsAttribute(
    string origins,
    string headers,
    string methods
)

详细的参数解释请查看MSDN。

知道了EnableCorsAttribute类的构造函数以后,我们可以使用下面的方法进行改进。

方法一:在Web.Config文件的appSettings节点里面配置参数:

然后修改WebApiConfig.cs文件的Register方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Configuration;

namespace WebApi
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            #region 跨域配置
            string allowedOrigin = ConfigurationManager.AppSettings["allowedOrigin"];
            string allowedHeaders = ConfigurationManager.AppSettings["allowedHeaders"];
            string allowedMethods = ConfigurationManager.AppSettings["allowedMethods"];
            config.EnableCors(new EnableCorsAttribute(allowedOrigin, allowedHeaders, allowedMethods));
            #endregion
            // Web API 路由
            config.MapHttpAttributeRoutes();

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

方法二:如果只想对某些api或者api里面的某些方法做跨域,可以直接在API控制器类上面使用特性标注或者在方法上面使用特性标注。

允许Student控制器可以跨域:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Net;
 5 using System.Net.Http;
 6 using System.Web.Http;
 7 using WebApi.Entity;
 8 using System.Web.Http.Cors;
 9
10 namespace WebApi.WebApiController
11 {
12     [EnableCors(origins:"http://localhost:34352",headers:"*",methods:"GET,POST,PUT,DELETE")]
13     public class StudentController : ApiController
14     {
15         public static List<Student> studentList = InitStudentList();
16
17         private static List<Student> InitStudentList()
18         {
19             return new List<Student>()
20             {
21              new Student {StudentID =1,StudentName="唐僧",Age=24,Sex="男",Major="师范"},
22                 new Student {StudentID =2,StudentName="孙悟空",Age=579,Sex="男",Major="管理"},
23                new Student {StudentID =3,StudentName="沙悟净",Age=879,Sex="男",Major="水利工程"},
24                new Student {StudentID =4,StudentName="白骨精",Age=456,Sex="女",Major="表演"},
25                new Student {StudentID =5,StudentName="玉兔精",Age=456,Sex="女",Major="舞蹈"}
26             };
27         }
28
29         [HttpGet]
30         public IHttpActionResult GetAllStudent()
31         {
32             return Json<List<Student>>(studentList);
33         }
34     }
35 }

只允许Student控制器里面的GetAllStudent方法可以跨域:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Net;
 5 using System.Net.Http;
 6 using System.Web.Http;
 7 using WebApi.Entity;
 8 using System.Web.Http.Cors;
 9
10 namespace WebApi.WebApiController
11 {
12
13     public class StudentController : ApiController
14     {
15         public static List<Student> studentList = InitStudentList();
16
17         private static List<Student> InitStudentList()
18         {
19             return new List<Student>()
20             {
21              new Student {StudentID =1,StudentName="唐僧",Age=24,Sex="男",Major="师范"},
22                 new Student {StudentID =2,StudentName="孙悟空",Age=579,Sex="男",Major="管理"},
23                new Student {StudentID =3,StudentName="沙悟净",Age=879,Sex="男",Major="水利工程"},
24                new Student {StudentID =4,StudentName="白骨精",Age=456,Sex="女",Major="表演"},
25                new Student {StudentID =5,StudentName="玉兔精",Age=456,Sex="女",Major="舞蹈"}
26             };
27         }
28
29         /// <summary>
30         /// 允许跨域
31         /// </summary>
32         /// <returns></returns>
33         [EnableCors(origins: "http://localhost:34352", headers: "*", methods: "GET,POST,PUT,DELETE")]
34         [HttpGet]
35         public IHttpActionResult GetAllStudent()
36         {
37             return Json<List<Student>>(studentList);
38         }
39
40         /// <summary>
41         /// 不允许跨域
42         /// </summary>
43         [HttpPost]
44         public void Post()
45         { }
46     }
47 }

原文地址:https://www.cnblogs.com/dotnet261010/p/8831450.html

时间: 2024-08-28 09:34:31

Web API(七):Web API跨域问题的相关文章

基于JWT的web api身份验证及跨域调用实践

随着多终端的出现,越来越多的站点通过web api restful的形式对外提供服务,很多网站也采用了前后端分离模式进行开发,因而在身份验证的方式上可能与传统的基于cookie的Session Id的做法有所不同,除了面临跨域提交cookie的烦人问题外,更重要的是,有些终端可能根本不支持cookie. Json Web Token(jwt)是一种不错的身份验证及授权方案,简单的说就是调用端调用api时,附带上一个由api端颁发的token,以此来验证调用者的授权信息.但由于时间关系,不对jwt

直接用postman测试api ,服务器端没提供跨域也可以访问。

1. 直接用postman测试api ,服务器端没提供跨域也可以访问. 但是,如果用本地的 sever 搭的server, 然后去访问api的话,浏览器会提示 跨域错误.

Web Api 2(Cors)Ajax跨域访问

支持Ajax跨域访问ASP.NET Web Api 2(Cors)的简单示例教程演示 随着深入使用ASP.NET Web Api,我们可能会在项目中考虑将前端的业务分得更细.比如前端项目使用Angularjs的框架来做UI,而数据则由另一个Web Api 的网站项目来支撑.注意,这里是两个Web网站项目了,前端项目主要负责界面的呈现和一些前端的相应业务逻辑处理,而Web Api则负责提供数据. 这样问题就来了,如果前端通过ajax访问Web Api项目话,就涉及到跨域了.我们知道,如果直接访问,

浅谈Web Api配合SignalR的跨域支持

最近接手的一个项目中,涉及到一个简单的消息模块,由于之前有简单了解过SignalR,所以打算尝试着摸索摸索~! 首先,通过Nuget管理器添加Microsoft ASP.NET SignalR引用~目前最新版本2.2.0,依赖项目也有点多,什么Microsoft.AspNet.SignalR.JS,Microsoft.AspNet.SignalR.SystemWeb,还有Owin相关的项目,没法咯,一起统一引用! 添加启动设置 1 [assembly: OwinStartup(typeof(Si

Web安全技术(3)-浏览器的跨域访问

http://www.blogjava.net/linli/archive/2015/04/22/424584.html 一.浏览器介绍 对于Web应用来说,浏览器是最重要的客户端. 目前浏览器五花八门多得不得了,除了Chrome.IE.Firefox.Safari.Opera这些国外的浏览器外,百度.腾讯.360.淘宝.搜狗.傲游之类的,反正能做的都做了. 浏览器虽然这么多,但浏览器内核主要就以下4种: Trident:IE使用的内核. Gecko:Firefox使用的内核. WebKit:S

web api 解决跨域的问题

web api 总是会遇到跨域的问题,今天我找到了如下方法解决跨域: 1: a:在配置文件中的 加上如下代码 <system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers"

ASP.NET Core Web API 跨域(CORS) Cookie问题

身为一个Web API,处理来自跨域不同源的请求,是一件十分合理的事情. 先上已有的文章,快速复制粘贴,启用CORS: Microsoft:启用 ASP.NET Core 中的跨域请求 (CORS) ASP.NET Core 配置跨域(CORS) 如果按照以上文章,一步一步操作,你会发现,虽然能跨域请求了,但是即使客户端开了(xhr.withCredentials = true)也无法将Cookie发送给API. 关于AllowAnyOrigin 这是因为请求的首部中携带了 Cookie 信息,

No &#39;Access-Control-Allow-Origin&#39; header is present on the requested resource——Web Api跨域问题

最近使用C#写了一个简单的web api项目,在使用项目中的.cshtml文档测试的时候没有任何问题,但是在外部HBuilder上面编写.html通过Ajax调用web api路径时报错: No 'Access-Control-Allow-Origin' header is present on the requested resource. 导致这个问题的原因是在跨域访问web api的api时,C#自带的web api并不能支持跨域访问,如果需要,可以更改配置来实现. 1.更改Web.con

在ABP的Web层中实现复杂请求跨域访问

在最近的项目中,后端使用ABP,前端采用React,前后端完全分离.其中大部分接口都通过WebApi层调用,项目中未使用Session.但最后在做一个留言的验证码时,使用了Session验证的方式,所以将验证码请求与校验功能放在了Web层.由于测试阶段前后端不同域,涉及到跨域请求的问题.跨域问题可以通过代理等手段解决,但是也可以在后端做些简单的修改来进行实现.WebApi的跨域处理比较简单,有官方给出的解决方案.但是Web层一般不涉及跨域,所以自己进行了探索实现. 一.常见方案 在web.con

七牛---以一个七牛上传的实例小结下AJAX跨域【转】

http://blog.csdn.net/netdxy/article/details/50699842 使用七牛过程中,很多用户或多或少遇到跨域的问题,这篇文章主要介绍下跨域的概念来看什么情况下会出现跨域以及七牛关于跨域的策略. 关于跨域的,说白点就是去别服务器上取东西,域当然是别的服务器,只要协议.域名.端口有任何一个不同,都被当作是不同的域.这里以表单上传结合AJAX请求获取Token上传的Demo为切入点具体看下什么时候会出现跨域. 以下是Demo的代码示例,需要注意的是请求token的