浏览器的同源策略,及如可跨域
分类:
IT文章
•
2023-11-14 22:12:54
1、同源策略
所谓同源是指,域名,协议,端口相同。当一个浏览器的打开一个页面时中,页面请求非同源的URL时,请求能正常响应,但是浏览器会判断请求的URL和本页面的URL是否同源,
如果非同源的话,就会在本页面返回一个错误,并且得不到返回的数据。
2、解决跨域的方法
2.1、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的。
对于简单的请求只需要我么请求URL的响应函数views里面配置响应头Access-Control-Allow-Origin
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function func(name) {
alert(name)
}
</script>
<script src="http://127.0.0.1:8001/base/"></script>
</head>
<body>
<form>
<input type="button" id="id_button" value="button">
</form>
<script src="/static/jquery-2.1.4.min.js"> </script>
<script>
$("#id_button").click(function () {
$.ajax({
url:'http://127.0.0.1:8001/base/',
type:'GET',
success:function () {
alert('1111')
}
})
})
</script>
</body>
</html>
index.html
from django.shortcuts import render,HttpResponse
def index(request):
return render(request,'index.html')
def base(request):
response = HttpResponse('func("wuzhiib")')
response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
# 在我们请求的URL的views里面设置,’*‘表示允许所有URL通过
return response
views.py
浏览器对简单请求和复杂请求的处理是不一样的
* 简单请求和非简单请求的区别?
简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。
* 关于“预检”
- 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
=> 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
Access-Control-Request-Method
=> 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
Access-Control-Request-Headers
如果在Ajax请求中加入ContentType就会使普通的请求变成复杂的请求。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function func(name) {
alert(name)
}
</script>
<script src="http://127.0.0.1:8001/base/"></script>
</head>
<body>
<form>
<input type="button" id="id_button" value="button">
</form>
<script src="/static/jquery-2.1.4.min.js"> </script>
<script>
$("#id_button").click(function () {
$.ajax({
url:'http://127.0.0.1:8001/base/',
type:'GET',
contentType:'application/json',
success:function () {
alert('1111')
}
})
})
</script>
</body>
</html>
index.html
对对于复杂的请求要在对应的头里面做设置,Contenttype只需要在响应头里面设置X-Content-Type-Options
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
# Create your views here.
def index(request):
return render(request,'index.html')
def base(request):
response = HttpResponse('func("wuzhiib")')
response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
return response
views.py
3、JsonP实现跨域
非同源的URL不能阻止src属性的请求,也就是说通过src属性我们能跨域请求数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function func(name) {
alert(name)
}
</script>
<!--利用script标签来实现跨域请求,返回的是func(''wuzhibin),相当于实现上面func函数的调用-->
<script src="http://127.0.0.1:8001/base/"></script>
</head>
<body>
<form>
<input type="button" id="id_button" value="button">
</form>
<script src="/static/jquery-2.1.4.min.js"> </script>
<script>
$("#id_button").click(function () {
$.ajax({
url:'http://127.0.0.1:8001/base/',
type:'GET',
contentType:'application/json',
success:function () {
alert('1111')
}
})
})
</script>
</body>
</html>
index.html
from django.shortcuts import render,HttpResponse
def index(request):
return render(request,'index.html')
def base(request):
response = HttpResponse('func("wuzhiib")')
response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
#浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
response['X-Content-Type-Options'] ="application/json"
return response
views.py
注意如果如果不配之响应头的X-Content-Type-Options属性,浏览器会报一个错误

上面就是Jsonp实现的原理,这个只是哟个简单的例子,一般我们都需要能够动态的实现标签的创建
动态创建script标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->
<script>
function addScriptTag(src){
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.head.appendChild(script);
// document.body.removeChild(script);
}
// 接受返回数据的回调函数
function func(name){
alert("hello"+name)
}
function f(){
addScriptTag("http://127.0.0.1:8001/base/")
}
</script>
</body>
</html>
index.Html
views.py与上面一直
from django.shortcuts import render,HttpResponse
def index(request):
return render(request,'index.html')
def base(request):
response = HttpResponse('func("wuzhiib")')
response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
#浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
response['X-Content-Type-Options'] ="application/json"
return response
views.py
上面的例子中,我们在前端定义函数的时,另一个域明显是不知道我们我们前端定义的是func的,所以我们需要将函数名传给跨域的views函数动态生成返回函数名
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->
<script>
function addScriptTag(src){
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.head.appendChild(script);
// document.body.removeChild(script);
}
// 接受返回数据的回调函数
function func(name){
var name=name
alert("hello"+name)
}
function f(){
addScriptTag("http://127.0.0.1:8001/base/?callbacks=func")
}
</script>
</body>
</html>
index.html
from django.shortcuts import render,HttpResponse
def index(request):
return render(request,'index.html')
def base(request):
# 返回给跨域请求的数据
data = 'wuzhibin'
#获取跨域请求的函数名
callback = request.GET.get('callbacks')
print(callback)
response = HttpResponse("%s('%s')"%(callback,data))
response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
#浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
response['X-Content-Type-Options'] ="application/json"
return response
view.py
Ajax中使用Jsonp
在实际的用处中,在Ajax中使用跨站请求数据的场景比较多一些。而不是单独生产动态生成一个Script标签去请求数据
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
def index(request):
return render(request,'index.html')
def base(request):
import json
# 返回给跨域请求的数据,一般都是字典的格式
data = {
'key1':'value1',
'key2':'value2',
'k3':'value3',
'k4':'value4',
}
#等到跨域的方法名
callbacks = request.GET.get("callbacks")
response =HttpResponse("%s('%s')"%(callbacks,json.dumps(data)))
response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
#浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
response['X-Content-Type-Options'] ="application/json"
return response
views.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->
<script>
function f(){
$.ajax({ //大家会发现我的type请求方法没写,默认是get请求
url:"http://127.0.0.1:8001/base/",
dataType:"jsonp",
jsonp: 'callbacks',
jsonpCallback:"SayHi"
});
}
function SayHi(arg){
// 将字符串转发为字典的格式
var data = JSON.parse(arg);
alert(data.key1); //k1是后端返回的数据中的键值对的键
}
</script>
</body>
</html>
index.html
也能通过Ajax的success函数获取跨域的数据,这种方式比较简单些
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->
<script>
function f(){
$.ajax({ //大家会发现我的type请求方法没写,默认是get请求
url:"http://127.0.0.1:8001/base/",
dataType:"jsonp",
jsonp: 'callbacks',
jsonpCallback:"SayHi",
success:function (rag) {
var data = JSON.parse(rag)
alert(data.key1)
}
});
}
</script>
</body>
</html>
index.html
views.py函数和上面保持一致