一 同源和跨域
简单请求跨域
我们创建两个django项目,第一个叫做pro01,一个叫做pro02,pro01用8000端口启动,pro02用8001端口启动
pro01项目的index.html文件内容如下:
{% load static %}<!DOCTYPE html><html lang="zh-CN"><head> <meta charset="utf-8"> 告诉浏览器安装IE的最高版本渲染浏览器--> <meta http-equiv="X-UA-Compatible" content="IE=edge"> 整个网站和等比缩放,目的兼容:移动端,web端。可以完整访问网站--> <meta name="viewport" content="width=device-width, initial-scale=1"> 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>标题title> Bootstrap 引入文件 --> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet">head><body><h1>你好,我是pro1的index页面!h1><button type="button" id="btn">提交button><script src="{% static 'jquery-3.5.1.js' %}">script><script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}">script><script> $("#btn").click(function () { $.ajax( { url:"http://127.0.0.1:8001/index/", type:"get", success:function (response) { console.log(response) } } ) })script>body>html>
urls.py文件内容如下:
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name="index"), ]
vews.py内容如下:
def index(request): return render(request,'index.html')
pro02项目的urls.py内容如下:
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index,name="index"), ]
view.py内容如下:
from django.http import JsonResponsedef index(request): a={"name":"zxb"} ret = JsonResponse(a) #解决跨越 #指定域名访问:只允许http://127.0.0.1:8000这个域名访问 ret["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000" #只有这个ip和端口来的请求,我才给他数据,其他你浏览器帮我拦着 #所有域名都可以访问 # ret['Access-Control-Allow-Origin']="*" return ret
如果不加ret["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000"就会造成跨域
加ret["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000"解决跨域问题
可以添加多个
ret["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000,http://127.0.0.1:8002"
二 CORS通信实现跨域
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求
(1) 请求方法是以下三种方法之一:(也就是说如果你的请求方法是什么put、delete等肯定是非简单请求) 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,也就是说,如果你发送的application/json格式的数据,那么肯定是非简单请求,vue的axios默认的请求体信息格式是json的,ajax默认是urlencoded的。
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
* 简单请求和非简单请求的区别? 简单请求:一次请求 非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。* 关于“预检”- 请求方式:OPTIONS- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息- 如何“预检” => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Headers
看图:
支持跨域,简单请求
服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'
支持跨域,复杂请求:复杂请求跨域 需要经过两个请求,第一个预检option请求,第二个正常的请求
由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。
“预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
“预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
举个复杂请求例子:
pro01模版内容:
{% load static %}<!DOCTYPE html><html lang="zh-CN"><head> <meta charset="utf-8"> 告诉浏览器安装IE的最高版本渲染浏览器--> <meta http-equiv="X-UA-Compatible" content="IE=edge"> 整个网站和等比缩放,目的兼容:移动端,web端。可以完整访问网站--> <meta name="viewport" content="width=device-width, initial-scale=1"> 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! --> <title>标题title> Bootstrap 引入文件 --> <link href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" rel="stylesheet">head><body><h1>你好,我是pro1的index页面!h1><button type="button" id="btn">提交button><script src="{% static 'jquery-3.5.1.js' %}">script><script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}">script><script> $("#btn").click(function () { $.ajax( { url:"http://127.0.0.1:8001/index/", type:"get", contentType:"application/json", data:JSON.stringify({a1:"xxxxx"}), success:function (response) { console.log(response) } } ) })script>body>html>
pro02views内容:
def index(request): a={"name":"zxb"} ret = JsonResponse(a) #解决跨越 ret["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000" #任何content-type类型都接受,浏览器不要拦截 ret["Access-Control-Allow-Headers"] = "content-type" return ret
如果不加ret["Access-Control-Allow-Headers"] = "content-type"
加了解决问题了