跨域(CORS)产生原因分析与解决方案。
产生跨域的原因?
当一个请求在浏览器发出的时候,服务器会接受并且也会处理和响应。只不过浏览器在解析这个请求响应之后,发现不属于浏览器的同源策略(地址里面的协议,域名,端口都不相同),也没有包含正确的cors响应头,返回的结果就会被拦截。
预检请求
预检请求是在发送实际请求之前,客户端会先发送一个options方法的请求向服务器确认,如果通过之后就会发送真正的请求,这样可以避免跨域对服务器的用户数据造成的影响。
预检请求定义
CORS分为简单请求和非简单请求。简单请求即为:请求方法为get、post、head,请求头为text/plain、multipart/form-data、application/x-www-form-urlencoded属于简单请求,不会触发CORS预检请求。 非简单请求例如为:Content-Type:application/json就会触发CORS请求。 非简单请求Request Headers:
OPTIONS /api/data HTTP/1.1 Host: 127.0.0.1:3011 Access-Control-Request-Method: PUT Access-Control-Request-Headers: content-type,test-cors Origin: http://127.0.0.1:3010 Sec-Fetch-Mode: cors
可以看出options是预检请求使用的方法,该方法是在http/协议中所定义,还有一个重要的字段origin请求表示请求来自哪个源。服务器可以根据这个字段来判断是否是合法的请求源。 Access-Control-Request-Method:告诉服务器请求的方法。 Access-Control-Request-Headers:告诉服务器,实际请求头部字段
设置服务器
res.writeHead(200, { 'Access-Control-Allow-Origin': 'http://127.0.0.1:3010', 'Access-Control-Allow-Headers': 'Test-CORS, Content-Type', 'Access-Control-Allow-Methods': 'PUT,DELETE', 'Access-Control-Max-Age': 86400 });
解释一下: Access-Control-Allow-Origin:表示‘http://127.0.0.1:3010’这个请求源是可以使用的,该字段设置为‘*’表示允许任意跨域源请求。 Access-Control-Allow-Methods:表示服务器允许客户端使用 PUT、DELETE 方法发起请求,可以一次设置多个,表示服务器所支持的所有跨域方法,而不单是当前请求那个方法,这样好处是为了避免多次预检请求。 Access-Control-Allow-Headers:表示服务器允许请求中携带 Test-CORS、Content-Type 字段,也可以设置多个。 Access-Control-Max-Age 表示该响应的有效期,单位为秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。还有一点需要注意,该值要小于浏览器自身维护的最大有效时间,否则是无效的。
如何解决跨域
1.后端配置方案
router.all('/getCityList', function(req,res,next){
//*表示支持所有网站访问,也可以额外配置相应网站
res.header('Access-Control-Allow-Origin','*')
next()
2.JSONP 方式
$.ajax({
type:"get",
async:false,
url:"http://localhost:8080/JavaWeb01/getPassWordByUserNameServlet?userName=Tom",
dataType:"jsonp",//数据类型为jsonp
jsonp:"backFunction",//服务端用于接收callBack调用的function名的参数
success:function (data) {
lert(data["passWord"]);
},
error:function () {
alert("error");
}
});
3.nginx 代理