总结自慕课网:ajax跨域完全讲解,并且原视频中后台为JAVA
,这里改成了Python
。
什么是AJAX
跨域
只要协议、域名、端口有任何一个不同,都被当作是不同的域,不同域之间的请求就是跨域操作。AJAX
跨域就是AJAX
在A
域下对B
域发送了请求,一般情况下会被浏览器禁止。
例如,后台开启两个Flask
服务器ServerA(port=8080)
和ServerB(port=8081)
:ServerA.py
代码如下:
from flask import Flask,render_template app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route('/get') def get(): return 'get8080 ok' if __name__ == "__main__": app.run(port=8080)
ServerB.py
代码如下:
from flask import Flask app = Flask(__name__) @app.route('/get') def get(): return 'get8081 ok' if __name__ == "__main__": app.run(port=8081)
index.html
使用jQuery
发送ajax
请求,代码如下:
<!DOCTYPE html> <html> <head> <title>Index</title> </head> <body> <h3>Test</h3> <button onclick="get1()">GET 8080</button> <button onclick="get2()">GET 8081</button> </body> <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script type="text/javascript"> function get1(){ $.get("http://127.0.0.1:8080/get").then( function(res){ console.log(res); }) } function get2(){ $.get("http://127.0.0.1:8081/get").then( function(res){ console.log(res); }) } </script> </html>
因此GET 8080
和GET 8081
两个按钮是分别向8080/8081
端口发送请求,并将结果打印在控制台。开启两个服务器,在浏览器输入127.0.0.1:8080进入index
页面,打开Chrome
控制台并依次点击,结果如图:
可以看到GET 8080
正常输出,而由于8081
端口的请求属于跨域,浏览器报错并未正常打印结果。
如何处理AJAX
跨域问题
1.关闭浏览器安全策略
禁止跨域的AJAX
请求,是浏览器本身的安全策略,实际上后台并没有限制,例如点击GET 8081
后,可以在NETWORK
中看到这个请求本身是OK
的:
因此只要关闭浏览器的安全策略即可,方式之一是在命令行中使用
"chrome.exe路径" --disable-web-security --user-data-dir=D:\temp
打开浏览器,此时浏览器会有安全性提示,依次点击两个按钮,结果如图:
2.使用JSONP
AJAX
请求受到跨域的限制,其请求类型是xhr
,但html
页面在引用别的域的JS
脚本时却可以正常访问,这种请求的类型是script
,如图:
JSONP
的原理就是将原本的xhr
请求替换为script
请求,例如假设原先xhr
请求返回的是数据A
,JSONP
请求会附带一个callback
参数说明本地使用的回调函数,假设为func1
,后端收到这个JSONP
请求,返回的是JS
代码func1(A)
。使用JSONP
需要对前后端都做修改。在此不演示~
3.在ServerA
中修改
我们可以让后台服务器代替浏览器去请求跨域的接口,并将数据通过本域的接口返回给浏览器,使浏览器不再发送跨域请求。例如在ServerA.py
中增加一个接口如下:
@app.route('/get_8081_through_8080') def get2(): return requests.get('http://127.0.0.1:8081/get').text
index.html
增加一个button
,如下:
<button onclick="get3()">GET 8081 THROUGH 8080</button> <script type="text/javascript"> function get1(){ ... } function get2(){ ... } function get3(){ $.get("http://127.0.0.1:8080/get_8081_through_8080").then( function(res){ console.log(res); }) } </script>
此时对浏览器而言get3()
就不属于跨域的请求了,后台代替浏览器向8081
发送了请求。
结果如图所示,第二个button
由于跨域仍然报错,第三个button
则正常输出:
4.在ServerB
中修改
ServerB
也可以通过向浏览器返回特定响应头,告诉浏览器它是允许被跨域调用的,使用flask
的make_response
添加Access-Control-Allow-Origin
和Access-Control-Allow-Methods
两个字段,ServerB.py
更新如下:
from flask import Flask,Response app = Flask(__name__) @app.route('/get') def get(): return 'get8081 ok' @app.route('/get2') def get2(): resp = Response('get8081 ok by Access-Control-Allow') resp.headers['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8080' resp.headers['Access-Control-Allow-Methods'] = 'GET' return resp if __name__ == "__main__": app.run(port=8081)
将index.html
的get2()
方法请求的接口改为'http://127.0.0.1:8081/get2'
,依次点击button
,第二个button
已经可以正常输出内容: