跨域
以前使用flask框架的时候一直都是没有前后端分离 现在使用aiohttp框架 并且前端使用vue 前后端分离 因此出现了跨域的问题
不同浏览器对跨域的支持也是不一样的 支持跨域的浏览器主要有
- Chrome 3+
- Firefox 3.5+
- Opera 12+
- Safari 4+
- Internet Explorer 8+
标准的跨域请求默认是不发送任何的cookies的 如果需要把cookies作为请求的一部分 需要将请求 比如js底层的XMLHttpRequest请求的withCredentials属性设置为true
xhr.withCredentials = true;
相应的服务端那边需要设置Access-Control-Allow-Credentials为true来允许cookies的传送
Access-Control-Allow-Credentials: true
withCredentials属性将让request包含来自远程域的任何cookies 同时它也设置任何来自远程域的cookies 要注意这些cookies还遵循同域标准的 因此你的javascrpt代码不能访问来自document.cookie或者responset header的cookies 这些cookies只可以被远程域控制
除了javascrip代码需要根据浏览器对cors支持程度不一样需要恰当的作出跨域请求 例如如下代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46// Create the XHR object.
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
// Helper method to parse the title tag from the response.
function getTitle(text) {
return text.match('<title>(.*)?</title>')[1];
}
// Make the actual CORS request.
function makeCorsRequest() {
// This is a sample server that supports CORS.
var url = 'http://html5rocks-cors.s3-website-us-east-1.amazonaws.com/index.html';
var xhr = createCORSRequest('GET', url);
if (!xhr) {
alert('CORS not supported');
return;
}
// Response handlers.
xhr.onload = function() {
var text = xhr.responseText;
var title = getTitle(text);
alert('Response from CORS request to ' + url + ': ' + title);
};
xhr.onerror = function() {
alert('Woops, there was an error making the request.');
};
xhr.send();
}
服务端也需要一定的cors支持
在客户端和服务端之间的传输 一般客户端需要作出一些附加的headers和附加的请求 这些请求一般是隐藏的 但是可以抓包发现
跨域请求分类
- 简单跨域请求
- 不简单跨域请求
处理简单跨域请求
- HTTP方法是下面其中一种
- HEAD
- GET
- POST
- HTTP头部是
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type, 但是仅仅当值为
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
简单跨域请求这样命名的原因是因为他们可以让浏览器不做处跨域请求也可以访问到 比如JOPN请求或者html的表单form 这些情况不存在跨域的问题
一个有效的服务器response1
2
3
4Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
其中以下是跨域请求必须的
- Access-Control-Allow-Origin
Access-Control-Allow-Origin这个属性必须在server response的headers中 这个属性用来说明哪个域可以访问你的数据 如果缺少会导致跨域的失败 如果像让所有的域可以访问你的数据 那么可以使用*
Access-Control-Allow-Credentials默认来说 cookies是不可以包含在跨域请求中 使用这个属性说明cookies可以包含在跨域请求头部中 这个属性跟上面说到的withCredentials协同工作的(withCredentials是js客户端这边设置的 Access-Control-Allow-Credentials是服务端这边设置的)
Access-Control-Expose-Headers 在js的XMLHttpRequest 2对象中可以使用getResponseHeader()的方法来获取一个response的header 在跨域请求中 getResponseHeader()方法只可以获取简单的response header 简单的response header被定义为如下
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
如果像客户端可以获取其他的headers就需要使用Access-Control-Expose-Headers这个属性了
处理不简单跨域请求
不简单跨域请求在客户端看起来跟简单跨域请求差不多 但是它在有运行两个附加的请求
- 首先客户端会发送一个preflight request 这个请求用于获取服务端的允许来发送真正的请求
- 获取允许之后 客户端发送真正的请求
- 因为preflight request是可以被缓存的 所以不需要每次请求都发送一次preflight request
跨域例子
有以下api
http://localhost:8080/api/product/1
以上api可以获取以下json个格式对象1
2
3
4
5
6
7
8
9
10
11
12{
"id": 1,
"name": "pork",
"picture": "https://demo.pork.png",
"price": 53,
"description": "this is a pork",
"rating": 0.8,
"amount": 100,
"likes": 0,
"tag_id": 1,
"sales_permonth": 382
}
在一个html的script中使用jquery的$.get访问上面的api 因为需要从不同域名或者不同端口下加载资源 所以浏览器出于安全考虑会阻止这个api的访问 值得一提的是postman并不是严格按照这个标准的
测试跨域的html1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<html>
<head>
<title>cors_test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#submit").click(function() {
$.get("http://localhost:8080/api/product/1", function(data, status) {
alert("data:" + data + "\nStatus:" + status);
});
});
});
</script>
</head>
<body>
<button id="submit">submit</button>
</body>
</html>
结果 出现跨域请求被禁止的报错
aiohttp的跨域问题解决
因为aiohttp框架本身是不支持跨域的 所以我们需要使用一个拓展包aiohtto_cors
pip安装
pip install aiohttp_cors
具体使用方法请看aiohttp_cors
我系统分析与设计项目选择解决详情
结果 跨域请求成功
最后附加flask跨域问题解决方法flask_cors