Django 【第二十篇】后端CORS解决跨域问题
一、為什么會(huì)有跨域問題?
是因?yàn)闉g覽器的同源策略是對ajax請求進(jìn)行阻攔了,但是不是所有的請求都給做跨域,像是一般的href屬性,a標(biāo)簽什么的都不攔截。
?
二、解決跨域問題的兩種方式
- JSONP
- CORS?
?
三、JSONP
先簡單來說一下JSONP,具體詳細(xì)詳見上面JSONP
JSONP是json用來跨域的一個(gè)東西。原理是通過script標(biāo)簽的跨域特性來繞過同源策略。(創(chuàng)建一個(gè)回調(diào)函數(shù),然后在遠(yuǎn)程服務(wù)上調(diào)用這個(gè)函數(shù)并且將json數(shù)據(jù)形式作為參數(shù)傳遞,完成回調(diào))。
?
四、CORS跨域
隨著技術(shù)的發(fā)展,現(xiàn)在的瀏覽器可以主動(dòng)支持設(shè)置從而允許跨域請求,即:跨域資源共享(CORS,Cross-Origin Resource Sharing),其本質(zhì)是設(shè)置響應(yīng)頭,使得瀏覽器允許跨域請求。
1、簡單請求和復(fù)雜請求
條件:1、請求方式:HEAD、GET、POST2、請求頭信息:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type 對應(yīng)的值是以下三個(gè)中的任意一個(gè)application/x-www-form-urlencodedmultipart/form-datatext/plain注意:同時(shí)滿足以上兩個(gè)條件時(shí),則是簡單請求,否則為復(fù)雜請求2、簡單請求和復(fù)雜請求的區(qū)別?
簡單請求:一次請求
非簡單請求:兩次請求,在發(fā)送數(shù)據(jù)之前會(huì)先發(fā)第一次請求做‘預(yù)檢’,只有‘預(yù)檢’通過后才再發(fā)送一次請求用于數(shù)據(jù)傳輸。
3、關(guān)于預(yù)檢
- 請求方式:OPTIONS - “預(yù)檢”其實(shí)做檢查,檢查如果通過則允許傳輸數(shù)據(jù),檢查不通過則不再發(fā)送真正想要發(fā)送的消息 - 如何“預(yù)檢”=> 如果復(fù)雜請求是PUT等請求,則服務(wù)端需要設(shè)置允許某請求,否則“預(yù)檢”不通過Access-Control-Request-Method=> 如果復(fù)雜請求設(shè)置了請求頭,則服務(wù)端需要設(shè)置允許某請求頭,否則“預(yù)檢”不通過Access-Control-Request-Headers4、CORS的優(yōu)缺點(diǎn)
- CORS的優(yōu)點(diǎn):可以發(fā)任意請求
- CORS的缺點(diǎn):上是復(fù)雜請求的時(shí)候得先做個(gè)預(yù)檢,再發(fā)真實(shí)的請求。發(fā)了兩次請求會(huì)有性能上的損耗
?
五、JSONP和CORS的區(qū)別
JSONP:服務(wù)端不用修改,需要改前端。發(fā)jsonp請求
JSONP:只能發(fā)GET請求
CORS:前端的代碼不用修改,服務(wù)端的代碼需要修改。如果是簡單請求的話在服務(wù)端加上一個(gè)響應(yīng)頭。
CORS:可以發(fā)任意請求
?
六、基于CORS實(shí)現(xiàn)ajax請求
1、支持跨域,簡單請求
客戶端
index.html
<!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 οnclick="getData()">獲取用戶數(shù)據(jù)</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>
服務(wù)端
views.py 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、支持跨域,復(fù)雜請求
如果是復(fù)雜請求在你真正的發(fā)請求之前,會(huì)先偷偷的發(fā)一個(gè)OPTION請求,先預(yù)檢一下,我
允許你來你才來
如果想預(yù)檢通過就得寫個(gè)option請求
user.html <!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="獲取用戶數(shù)據(jù)" οnclick="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>user.html
服務(wù)端
from django.shortcuts import render,HttpResponse from django.http import JsonResponse from rest_framework.views import APIViewclass UserIndex(APIView):def get(self,request,*args,**kwargs):ret = {'code': 111,'data': '你好嗎?'}response = JsonResponse(ret)response['Access-Control-Allow-Origin'] = "*"return responsedef post(self,request,*args,**kwargs):print(request.POST.get('k1'))ret = {'code':1000,'data':'過年啦',}response = JsonResponse(ret)response['Access-Control-Allow-Origin'] = "*"return responsedef 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
由于復(fù)雜請求時(shí),首先會(huì)發(fā)送“預(yù)檢”請求,如果“預(yù)檢”成功,則發(fā)送真實(shí)數(shù)據(jù)。
- “預(yù)檢”請求時(shí),允許請求方式則需服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Request-Method
- “預(yù)檢”請求時(shí),允許請求頭則需服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Request-Headers
- “預(yù)檢”緩存時(shí)間,服務(wù)器設(shè)置響應(yīng)頭:Access-Control-Max-Age
3、跨域獲取響應(yīng)頭
默認(rèn)獲取到的所有響應(yīng)頭只有基本信息,如果想要獲取自定義的響應(yīng)頭,則需要再服務(wù)器端設(shè)置Access-Control-Expose-Headers。
a.html <!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body><p><input type="submit" οnclick="XmlSendRequest();" /></p><p><input type="submit" οnclick="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);// 獲取響應(yīng)頭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);// 獲取響應(yīng)頭console.log(xmlHttpRequest.getAllResponseHeaders());}})}</script> </body> </html>HTMLviews.py 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)
4、跨域傳輸cookie
在跨域請求中,默認(rèn)情況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書無論在預(yù)檢請求中或是在實(shí)際請求都是不會(huì)被發(fā)送。
如果想要發(fā)送:
- 瀏覽器端:XMLHttpRequest的withCredentials為true
- 服務(wù)器端:Access-Control-Allow-Credentials為true
- 注意:服務(wù)器端響應(yīng)的?Access-Control-Allow-Origin 不能是通配符 *
views.py 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)
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/xiaohema/p/8456591.html
總結(jié)
以上是生活随笔為你收集整理的Django 【第二十篇】后端CORS解决跨域问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL教程(一)—— 数据库设计
- 下一篇: 怎样实现一个简单的jQuery编程