一、问题:
服务器端代码
from flask import Flask from flask import make_response from flask import jsonify app = Flask(__name__) def cors_response(res): response = make_response(jsonify(res)) response.headers['Access-Control-Allow-Origin'] = '*' response.headers['Access-Control-Allow-Headers'] = 'content-type' return response @app.route("/api/order", methods=['GET', 'POST', 'OPTIONS']) def index(): print('request success') return cors_response({'code': 0, 'data': 'success'}) if __name__ == '__main__': app.run()
axios请求代码
axios.post('http://127.0.0.1:5000/api/order', {headers: {'Content-type': 'application/json', 'Access-Control-Allow-Origin': '*'}} )
运行结果
服务器端控制台结果
浏览器console控制台
二、CORS跨域原理
1.CORS简介
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
2.两种请求
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:
- HEAD
- GET
- POST
(2)HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
三、错误分析及解决
上述请求为非简单请求,请求过程
- 正式通信前,会有一次HTTP查询请求,称为‘预检’请求(preflight)。预检请求用的方法是OPTIONS,与控制台的结果符合
- 服务器接收预检请求后,通过检查origin,
Access-Control-Request-Method
和Access-Control-Request-Headers
字段以后,确认允许跨源请求,就可以做出回应。- 检查origin:response headers中的Access-Control-Allow-Origin的值是否包含发送请求的域名。
Access-Control-Allow-Origin: * 表示同意任意跨域请求
- 检查Access-Control-Request-Method:它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法,由于此次请求的方法是POST,服务器默认支持,因此不需要设置
- 如果浏览器请求包括
Access-Control-Request-Headers
字段,则Access-Control-Allow-Headers
字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。由于以上例子的浏览器请求添加了自定义的Access-Control-Allow-Origin字段,所以需要将服务器端的response.headers['Access-Control-Allow-Headers'] = 'content-type' 改为
response.headers['Access-Control-Allow-Headers'] = 'content-type, Access-Control-AllowOrigin'
- 检查origin:response headers中的Access-Control-Allow-Origin的值是否包含发送请求的域名。
参考: