在WebSiteA前台页面中请求WebSiteB的数据时,如果WebSiteA和WebSiteB的域名不一样(包括IP、端口)就会发生跨域。比如:www.websitea.com的某个前台页面请求www.websiteb.com/GetAllUser会发生跨域,但如果我们在浏览器地址栏直接输入www.websiteb.com/GetAllUser进行访问、用Postman进行访问、用后台http请求进行访问是不会跨域的,跨域是浏览器的一种安全机制。
前两篇文章介绍了WebApi项目的创建和测试,今天来说说WebApi跨域访问的问题。本篇主要介绍了利用CORS解决跨域问题一些细节和具体步骤,下面来看看吧。
既然是解决WebApi跨域问题,那WebApi(http://localhost:9002)和网站(http://localhost:57447)当然是单独部署了,只有这样WebApi服务和网站的域名才会不同,要不怎么出现垮域哇,主要代码如下:
[RoutePrefix("api/prefix")]
public class PleasureController : ApiController
{
[Route("Pleasure/GetOne/{age:int=16}")]
[HttpGet]
public IEnumerable GetOne(int age)
{
return new string[] { "GetOne(int age)->value1", "GetOne(int age)->value2" };
}
[HttpGet]
public string GetOne(int id, string name, int age)
{
return string.Format("GetOne(int id, string name, int age)->id={0},name={1},age={2}", id, name, age);
}
[HttpGet]
public string GetList()
{
return "GetList()->value";
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = @"\d*" }
);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
有了WebApi服务,现在我们新建一个网站项目,并在前台请求http://localhost:9002/api/Pleasure/GetOne/5?name=aa&age=12,看看是否会成功。
function invoke1() {
$.ajax({
type: "get",
url: "http://localhost:9002/api/Pleasure/GetOne/5",
contentType: "application/json",
data: "name=aaa&age=12",
dataType: "json",
success: function (data) {
$("#result").val(data);
},
error: function (data) {
}
});
}
CORS全称Cross-Origin Resource Sharing,中文全称跨域资源共享,是一种允许当前域的资源被其他域的脚本请求访问的机制。它解决跨域问题的原理是通过向http的请求报文和响应报文里面加入相应的标识告诉浏览器它能访问哪些域名的请求。比如我们向响应报文里面增加这个Access-Control-Allow-Origin:http://localhost:57447,就表示支持http://localhost:57447里面的所有请求访问系统资源。
三个*表示本服务支持任意请求来访问,实际中除了完全开放的服务,其他项目肯定不能这么干。到此为止跨域问题就已经解决了。
public static void Register(HttpConfiguration config)
{
//跨域配置
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = @"\d*" }
);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
此时再次出发按钮的点击事件,就能正常获取到结果了。
并不是所有的浏览器都支持CORS来解决跨域问题,如下图所示IE8、IE9需要进行单独处理,必须在调用处指定 jQuery.support.cors = true;。至于网上说的CORS对IE8、9的解决方案XDomainRequest是怎么回事,本文不做探讨。
jQuery.support.cors = true;
function invoke1() {
$.ajax({
type: "get",
url: "http://localhost:9002/api/Pleasure/GetOne/5",
contentType: "application/json",
data: "name=aaa&age=12",
dataType: "json",
success: function (data) {
$("#result").val(data);
},
error: function (data) {
}
});
}
第二步中使用的是config.EnableCors(new EnableCorsAttribute("*", "*", "*"));这样是很不安全的,现在设置为只允许某域名能访问
public static void Register(HttpConfiguration config)
{
//跨域配置
config.EnableCors(new EnableCorsAttribute("http://localhost:57447", "*", "*"));
//config.EnableCors(new EnableCorsAttribute("http://localhost:57777,http://localhost:57447", "*", "*"));
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = @"\d*" }
);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
若允许多个域名访问WebApi,可用逗号隔开,示例代码如下:
public static void Register(HttpConfiguration config)
{
//跨域配置
config.EnableCors(new EnableCorsAttribute("http://localhost:57777,http://localhost:57447", "*", "*"));
......
}
如果在代码中把跨域参数写死那每次想改配置就必须改代码,这很不方便,我们不如将跨域参数放到配置文件中,这样需要变动的时候只改配置文件即可。
如果只想让某个方法支持跨域访问的话,可以利用EnableCors特性来实现,EnableCors特性可以加到控制器、方法上,示例如下:
public class PleasureController : ApiController
{
[Route("Pleasure/GetOne/{age:int=16}")]
[HttpGet]
public IEnumerable GetOne(int age)
{
return new string[] { "GetOne(int age)->value1", "GetOne(int age)->value2" };
}
[EnableCors(origins: "http://localhost:57447", headers: "*", methods: "*")]
[HttpGet]
public string GetOne(int id, string name, int age)
{
return string.Format("GetOne(int id, string name, int age)->id={0},name={1},age={2}", id, name, age);
}
[HttpGet]
public string GetList()
{
return "GetList()->value";
}
}
感谢:
感谢懒得安分老哥分享的内容http://www.cnblogs.com/landeanfen/p/5177176.html