我们日常的项目开发时使用AJAX,传统的Ajax请求只能获取在同一个域名下面的资源,但是HTML5打破了这个限制,允许Ajax发起跨域的请求。浏览器是可以发起跨域请求的,比如你可以外链一个外域的图片或者脚本。但是Javascript脚本是不能获取这些资源的内容的,它只能被浏览器执行或渲染。主要原因还是出于安全考虑,浏览器会限制脚本中发起的跨站请求。(同源策略, 即JavaScript或Cookie只能访问同域下的内容)。跨域的解决方案有多重JSONP、Flash、Iframe等,当然还有CORS(跨域资源共享,Cross-Origin Resource Sharing)今天就来了解下CORS的原理,以及如何使用
一、CORS概述
跨源资源共享标准通过新增一系列 HTTP 头,让服务器能声明那些来源可以通过浏览器访问该服务器上的各类资源(包括CSS、图片、JavaScript 脚本以及其它类资源)。另外,对那些会对服务器数据造成破坏性影响的 HTTP 请求方法(特别是 GET 以外的 HTTP 方法,或者搭配某些MIME类型的POST请求),标准强烈要求浏览器必须先以 OPTIONS 请求方式发送一个预请求(preflight request),从而获知服务器端对跨源请求所支持 HTTP 方法。在确认服务器允许该跨源请求的情况下,以实际的 HTTP 请求方法发送那个真正的请求。服务器端也可以通知客户端,是不是需要随同请求一起发送信用信息(包括 Cookies 和 HTTP 认证相关数据)。
二、CORS原理
例如:域名A(http://a.example)的某 Web 应用程序中通过<img>标签引入了域名B(http://b.foo)站点的某图片资源(http://b.foo/image.jpg)。这就是一个跨域请求,请求http报头包含Origin: http://a.example,如果返回的http报头包含响应头 Access-Control-Allow-Origin: http://a.example (或者Access-Control-Allow-Origin: http://a.example),表示域名B接受域名B下的请求,那么这个图片就运行被加载。否则表示拒绝接受请求。
三、CORS跨域请求控制方法
1.http请求头
Origin: 普通的HTTP请求也会带有,在CORS中专门作为Origin信息供后端比对,表明来源域。
Access-Control-Request-Method: 接下来请求的方法,例如PUT,DELETE等等
Access-Control-Request-Headers: 自定义的头部,所有用setRequestHeader方法设置的头部都将会以逗号隔开的形式包含在这个头中
2.http响应头
然后浏览器再根据服务器的返回值判断是否发送非简单请求。简单请求前面讲过是直接发送,只是多加一个origin字段表明跨域请求的来源。然后服务器处理完请求之后,会再返回结果中加上如下控制字段
Access-Control-Allow-Origin: 允许跨域访问的域,可以是一个域的列表,也可以是通配符"*"。这里要注意Origin规则只对域名有效,并不会对子目录有效。即http://foo.example/subdir/ 是无效的。但是不同子域名需要分开设置,这里的规则可以参照同源策略
Access-Control-Allow-Credentials: 是否允许请求带有验证信息,XMLHttpRequest请求的withCredentials标志设置为true时,认证通过,浏览器才将数据给脚本程序。
Access-Control-Expose-Headers: 允许脚本访问的返回头,请求成功后,脚本可以在XMLHttpRequest中访问这些头的信息
Access-Control-Max-Age: 缓存此次请求的秒数。在这个时间范围内,所有同类型的请求都将不再发送预检请求而是直接使用此次返回的头作为判断依据,非常有用,大幅优化请求次数
Access-Control-Allow-Methods: 允许使用的请求方法,以逗号隔开
Access-Control-Allow-Headers: 允许自定义的头部,以逗号隔开,大小写不敏感
案例演示:
案例环境:客户端使用jQuery,服务端WebApi(2.2)。因本人使用.net语言,所以服务端就使用webApi来演示了。
第一步: 在解决方案中创建一个WebApi程序(MVC)域名:http://localhost:24066
ValuesContraoller控制器
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; namespace WebApi.Controllers { public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1","value2" }; } // GET api/values/5 public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id,[FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } } }
第二步:在Nuget中下载:Cors 并安装到WebApi项目中
当项目引入到WebApi中后,我们启用调试WebApi发现会报一下两个错误
第三步:在Nuget中下载:Help Page并安装到WebApi项目中
安装好后,我们在启用调试WebApi,发现报以下错误:
解决方法:去到WebApi项目的View文件夹下的Web.config文件中,修改Razor的版本,由原来的2.0.0.0修改为3.0.0.0
此时,起码在启用调试发现WebApi可以启用成功了。
第四步:新建一个MVC项目名字叫MvcApp 域名:http://localhost:24102
创建Home控制器,创建Index视图,我们在视图中写Ajax方法去请求WebApi下的ValuesContraoller控制器的Get方法
<html> <head> <Meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="~/Scripts/jquery-1.8.2.js"></script> </head> <body> </body> </html> <script type="text/javascript"> $(function () { $.ajax({ url: 'http://localhost:24066/api/values/5',type: "Get",success: function (data,textStatus) { alert(data); } }) }) </script>我们会发现浏览器中会监控到这个请求失败了,报以下错误
这时候我们就需要在webApi中项目中启用对CORS的支持。
去到WebApi项目的App_Start文件夹中找到WebApiconfig.cs文件,启用对CORS的支持
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) { config.EnableCors(); //启用对CORS的支持。 config.Routes.MapHttpRoute( name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional } ); config.EnableSystemDiagnosticsTracing(); } } }然后再WebApi项目中需要进行跨域访问的方法或者类上打上[EnableCors]特性标签即可
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using System.Web.Http.Cors; namespace WebApi.Controllers { public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1","value2" }; } // GET api/values/5 //打上这个特性后,这个方法即可接受http://localhost:24102的域名进行ajax跨域的get和post访问了 //当然我们也可以自己定义类似的EnableCors特性,以实现自己的功能 [EnableCors(origins: "http://localhost:24102",headers: "*",methods: "get,post")] public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id,[FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } } }
-------------
我们也可以定义我们自己的类似[EnableCors]功能的特性
如我们可以在WebApi项目下自定义一个Attribute特性。 这个特性将应用与类,方法上面(哪个方法或者类上打上了这个特性标签,那么它将会接受特性类构造函数中允许的地址进行ajax的跨域访问)
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebApi.Attributes { using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Web.Cors; using System.Web.Http.Cors; /// <summary> /// 表示允许跨域请求 /// </summary> [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,AllowMultiple = false)] public class ApiCorsPolicyAttribute : Attribute,ICorsPolicyProvider { private readonly CorsPolicy _policy; /// <summary> /// 表示允许跨域请求 /// </summary> public ApiCorsPolicyAttribute() { _policy = new CorsPolicy { AllowAnyMethod = true,AllowAnyHeader = true }; _policy.Origins.Add("http://localhost:24102"); _policy.Origins.Add("http://sedo.wec.com"); _policy.Origins.Add("http://xq.duy001.com"); _policy.Origins.Add("http://kuaiche.35.com"); _policy.Origins.Add("http://zhudeshou.qdqcewl.com"); _policy.Origins.Add("http://qtebb.tuieeguangdashi.cn"); } /// <summary> /// 表示允许跨域请求 /// </summary> /// <param name="origins">允许的Cors来源Url,默认对所有来源启用</param> public ApiCorsPolicyAttribute(string origins = null) { // Create a CORS policy. _policy = new CorsPolicy { AllowAnyMethod = true,AllowAnyHeader = true }; if (string.IsNullOrEmpty(origins)) { _policy.AllowAnyOrigin = true; } else { _policy.Origins.Add("http://localhost:24102"); _policy.Origins.Add("http://192.168.1.255:8089"); _policy.Origins.Add("http://192.168.1.255:8088"); _policy.Origins.Add("http://localhost:56005"); _policy.Origins.Add("http://198.18.0.290:8921"); _policy.Origins.Add("http://192.168.2.243:8693"); _policy.Origins.Add("http://xpmdex.webuy01.com"); origins.Split(',').ToList().ForEach(s => _policy.Origins.Add(s)); } } public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request,CancellationToken cancellationToken) { return Task.FromResult(_policy); } } }
在WebApi项目的类或者方法上使用这个特性标签
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using System.Web.Http.Cors; using WebApi.Attributes; namespace WebApi.Controllers { [ApiCorsPolicy] public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1","value2" }; } // GET api/values/5 //打上这个特性后,这个方法即可接受http://localhost:24102的域名进行ajax跨域的get和post访问了 //当然我们也可以自己定义类似的EnableCors特性,以实现自己的功能 //[EnableCors(origins: "http://localhost:24102",[FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } } }这个就可以进行跨域访问了。 原文链接:https://www.f2er.com/ajax/161610.html