解决跨域(CORS)问题
为什么会有跨域问题
是因为浏览器的同源策略是对ajax请求进行阻拦了,但是不是所有的请求都给做跨域,像是一般的href属性,a标签什么的都不拦截
解决跨域问题的两种方式
- JSONP 推荐参考
- CORS
JSONP
先简单来说一下JSONP,具体详细详见上面JSONP
JSONP是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。(创建一个回调函数,然后在远程服务上调用这个函数并且将json数据形式作为参数传递,完成回调)。
CORS跨域
随着技术的发展,现在的浏览器可以主动支持设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
1、简单请求和复杂请求
条件:
1、请求方式:HEAD、GET、POST
2、请求头信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 对应的值是以下三个中的任意一个
application/x-www-form-urlencoded
multipart/form-data
text/plain 注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
2、简单请求和复杂请求的区别?
简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发第一次请求做‘预检’,只有‘预检’通过后才再发送一次请求用于数据传输。
3、关于预检
- 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
=> 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
Access-Control-Request-Method
=> 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
Access-Control-Request-Headers
4、CORS的优缺点
- CORS的优点:可以发任意请求
- CORS的缺点:上是复杂请求的时候得先做个预检,再发真实的请求。发了两次请求会有性能上的损耗
JSONP和CORS的区别
JSONP:服务端不用修改,需要改前端。发jsonp请求
JSONP:只能发GET请求
CORS:前端的代码不用修改,服务端的代码需要修改。如果是简单请求的话在服务端加上一个响应头。
CORS:可以发任意请求
基于CORS实现ajax请求
1、支持跨域,简单请求
客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width">
<title>Title</title>
</head>
<body>
<div>
<h1>欢迎来到我的主页</h1>
<button onclick="getData()">获取用户数据</button>
</div>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
function getData() {
$.ajax({
url:'http://127.0.0.1:8080/index/',
type:"GET",
success:function (data) {
console.log(data)
} })
}
</script>
</body>
</html>
服务端
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.views import APIView # Create your views here.
class IndexView(APIView):
def get(self,request,*args,**kwargs):
ret = {
'code': 111,
'data': '你好吗?'
}
response = JsonResponse(ret)
response['Access-Control-Allow-Origin'] = "*"
return response
2、支持跨域,复杂请求
如果是复杂请求在你真正的发请求之前,会先偷偷的发一个OPTION请求,先预检一下,我
允许你来你才来
如果想预检通过就得写个option请求
客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width">
<title>Title</title>
</head>
<body>
<input type="button" value="获取用户数据" onclick="getUser()">
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
function getUser() {
$.ajax({
url:'http://127.0.0.1:8080/user/',
type:'POST',
data:{'k1':'v1'},
headers:{
'h1':'sdfdgfdg'
},
success:function (ret) {
console.log(ret)
}
})
}
</script>
</body>
</html>
服务端
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView class UserIndex(APIView):
def get(self,request,*args,**kwargs):
ret = {
'code': 111,
'data': '你好吗?'
}
response = JsonResponse(ret)
response['Access-Control-Allow-Origin'] = "*"
return response def post(self,request,*args,**kwargs):
print(request.POST.get('k1'))
ret = {
'code':1000,
'data':'过年啦',
}
response = JsonResponse(ret)
response['Access-Control-Allow-Origin'] = "*"
return response def options(self, request, *args, **kwargs):
# self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
# self.set_header('Access-Control-Allow-Headers', "k1,k2")
# self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
# self.set_header('Access-Control-Max-Age', 10) response = HttpResponse()
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Headers'] = 'h1'
# response['Access-Control-Allow-Methods'] = 'PUT'
return response
由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。
- “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
- “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
- “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
3、跨域获取响应头
默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers
客户端
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="submit" onclick="XmlSendRequest();" />
</p> <p>
<input type="submit" onclick="JqSendRequest();" />
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function XmlSendRequest(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
var result = xhr.responseText;
console.log(result);
// 获取响应头
console.log(xhr.getAllResponseHeaders());
}
};
xhr.open('PUT', "http://c2.com:8000/test/", true);
xhr.setRequestHeader('k1', 'v1');
xhr.send();
} function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'PUT',
dataType: 'text',
headers: {'k1': 'v1'},
success: function(data, statusText, xmlHttpRequest){
console.log(data);
// 获取响应头
console.log(xmlHttpRequest.getAllResponseHeaders());
}
})
} </script>
</body>
</html> HTML
服务端
class MainHandler(tornado.web.RequestHandler): def put(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.set_header('xxoo', "seven")
self.set_header('bili', "daobidao") self.set_header('Access-Control-Expose-Headers', "xxoo,bili") self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Headers', "k1,k2")
self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
self.set_header('Access-Control-Max-Age', 10) Tornado
4、跨域传输cookie
在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。
如果想要发送:
- 浏览器端:XMLHttpRequest的withCredentials为true
- 服务器端:Access-Control-Allow-Credentials为true
- 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
客户端 浏览器html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body> <p>
<input type="submit" onclick="XmlSendRequest();" />
</p> <p>
<input type="submit" onclick="JqSendRequest();" />
</p> <script type="text/javascript" src="jquery-1.12.4.js"></script>
<script>
function XmlSendRequest(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
var result = xhr.responseText;
console.log(result);
}
}; xhr.withCredentials = true; xhr.open('PUT', "http://c2.com:8000/test/", true);
xhr.setRequestHeader('k1', 'v1');
xhr.send();
} function JqSendRequest(){
$.ajax({
url: "http://c2.com:8000/test/",
type: 'PUT',
dataType: 'text',
headers: {'k1': 'v1'},
xhrFields:{withCredentials: true},
success: function(data, statusText, xmlHttpRequest){
console.log(data);
}
})
} </script>
</body>
</html> HTML
服务端视图
class MainHandler(tornado.web.RequestHandler): def put(self):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Credentials', "true") self.set_header('xxoo', "seven")
self.set_header('bili', "daobidao")
self.set_header('Access-Control-Expose-Headers', "xxoo,bili") self.set_cookie('kkkkk', 'vvvvv'); self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs):
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")
self.set_header('Access-Control-Allow-Headers', "k1,k2")
self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")
self.set_header('Access-Control-Max-Age', 10)
在Django中间件中解决跨域问题
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__() def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response class CORSMiddleware(MiddlewareMixin):
def process_response(self,request,response):
# 添加响应头
# 允许你的域名来获取我的数据
# response['Access-Control-Allow-Origin'] = "*"
# 允许你携带Content-Type请求头
# response['Access-Control-Allow-Headers'] = "Content-Type"
# 允许你发送DELETE,PUT
# response['Access-Control-Allow-Methods'] = "DELETE,PUT"
response['Access-Control-Allow-Origin'] = "*"
if request.method == "OPTIONS":
response['Access-Control-Allow-Headers'] = "Content-Type"
response['Access-Control-Allow-Methods'] = "PUT,DELETE"
return response
解决跨域(CORS)问题的更多相关文章
- springmvc 解决跨域CORS
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import ja ...
- 一步一步学习SignalR进行实时通信_3_通过CORS解决跨域
原文:一步一步学习SignalR进行实时通信_3_通过CORS解决跨域 一步一步学习SignalR进行实时通信\_3_通过CORS解决跨域 SignalR 一步一步学习SignalR进行实时通信_3_ ...
- springboot解决跨域问题(Cors)
1.对于前后端分离的项目来说,如果前端项目与后端项目部署在两个不同的域下,那么势必会引起跨域问题的出现. 针对跨域问题,我们可能第一个想到的解决方案就是jsonp,并且以前处理跨域问题我基本也是这么处 ...
- Spring Boot中通过CORS解决跨域问题
今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由Netscap ...
- SpringBoot配置Cors解决跨域请求问题
一.同源策略简介 同源策略[same origin policy]是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 什么是源 源[or ...
- c# WebApi之解决跨域问题:Cors
什么是跨域问题 出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容.由于这个原因,我们不同站点之间的数据访问会被拒绝. Cors解决跨域问 ...
- Web API中使用CORS解决跨域
Web API中使用Cros解决跨域 如果两个页面的协议,端口和域名都相同,则两个页面具有相同的源,注:IE不考虑端口,同源策略不会阻止浏览器发送请求,但是它会阻止应用程序看到响应.如下图所示 COR ...
- springboot中通过cors协议解决跨域问题
1.对于前后端分离的项目来说,如果前端项目与后端项目部署在两个不同的域下,那么势必会引起跨域问题的出现. 针对跨域问题,我们可能第一个想到的解决方案就是jsonp,并且以前处理跨域问题我基本也是这么处 ...
- Django使用jsonp和cors解决跨域请求问题
1.使用jsonp的方式解决跨域请求的问题 我启动两个django项目,然后使用的端口不一样,在项目1中通过ajax发请求给项目2,然后接受项目2发送过来的数据 先看项目1的ajax的代码 $(&qu ...
随机推荐
- UGUI 打图集
using UnityEngine; using System.Collections; using UnityEditor; using System.Collections.Generic; us ...
- N-城堡问题
1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####---#####---#---#####---# 2 # # | ...
- uva11990 动态逆序对
这题说的是给了一个数组,按照他给的顺序依次删除数,在删除之前输出此时的逆序对个数 我们用Fenwick树 维护这整个数列, C[i]是一个 treap的头, 管理了在树状数组中 能影响他的点,然后我们 ...
- HTML标签-----article、aside、figure、nav和section
article <article> 标签定义独立的内容 <!DOCTYPE html> <html> <head> <meta cha ...
- mysql 创建用户,删除用户,增加权限
1,查询mysql 数据库已经存在的用户: SELECT USER,HOST FROM MYSQL.USER; 2,创建mysql 用户: '; USERNAME:用户名 HOST:主机,PASSWO ...
- numpy数学数据处理
数学和统计方法 sum 对数组中全部或某轴向的元素求和.零长度的数组的sum为0. mean 算术平均数.零长度的数组的mean为NaN. import numpy as np import nump ...
- Codeforce 296A - Yaroslav and Permutations
Yaroslav has an array that consists of n integers. In one second Yaroslav can swap two neighboring a ...
- Symfony2 学习笔记之控制器
一个controller是你创建的一个PHP函数,它接收HTTP请求(request)并创建和返回一个HTTP回复(Response).回复对象(Response)可以是一个HTML页面,一个XML文 ...
- Spring Boot 中使用 @ConfigurationProperties 注解
@ConfigurationProperties 主要作用:绑定 application.properties 中的属性 例如: @Configuration public class DataSou ...
- 自动部署war包脚本
war 包所在路径为:/home/wars/ROOT.war tomcat 所在路径为: ①:/home/search-3 ②:/home/search-4 部署单个war到一个tomcat中 #!/ ...