同源策略和跨域Ajaxjavascript
什麼是同源策略css
URL | 結果 | 緣由 |
http://store.company.com/dir2/other.html | 是 | |
http://store.company.com/dir/inner/another.html | 是 | |
https://store.company.com/secure.html | 不是 | 協議不相同 |
http://store.company.com:81/dir/etc.html | 不是 | 端口號不相同 |
http://news.company.com/dir/other.html | 不是 | 主機名不相同 |
127.0.0.1 www.fwd.com
127.0.0.1 www.khd.com html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script> </head> <body> <input type="button" value="提交" onclick="doajax();"/> <script> function doajax() { $.ajax({ url: 'http://www.fwd.com:8001/fwd', type: 'POST', data:{'k1':'v1'}, success: function (responseText, statusText) { }, error: function (event, errorText, errorType) { } }); } </script> </body> </html>
http://www.fwd.com:8001/fwdjava
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script> <script type="text/javascript" src='{{static_url("jquery.form.js")}}' charset="UTF-8"></script> </head> <body> 服務端 <script> </script> </body> </html>
此時點擊按鈕發起ajax請求後,能夠看到請求已被瀏覽器的同源策略阻止python
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script> </head> <body> <input type="button" value="跨域提交" onclick="doajax();"/> <script> //利用原生js本身建立一個跨域請求 function doajax() { //當點擊提交按鈕是執行函數 var tag = document.createElement('script'); //建立一個script標籤 tag.src = 'http://www.fwd.com:8001/fwd'; //設置script標籤的src地址,爲要請求數據的地址,由於src是不受同源策略 document.head.appendChild(tag); //將script標籤添加到head標籤裏面 document.head.removeChild(tag); //添加後會當即發送請求,因此這裏能夠將添加的script標籤刪除了 } //響應網站返回,shuju({'k1':'v1'}); 也就至關於返回了一個帶有參數的函數名稱 function shuju(shj) { //自定義執行函數,和響應網站返回的名稱相同,也就會執行自定義函數,而參數就是響應網站返回的數據 for(var i in shj){ //循環響應網站返回的數據 alert(i + ':' + shj[i]); //打印出數據的鍵和值 } } </script> </body> </html>
響應端jquery
import tornado.ioloop import tornado.web #導入tornado模塊下的web文件 class fwdHandler(tornado.web.RequestHandler): def get(self): #接收get請求 # self.render("fwd.html") self.write("shuju({'k1':'v1'});") #返回數據 def post(self): self.write("post請求成功") settings = { #html文件歸類配置,設置一個字典 "template_path":"views", #鍵爲template_path固定的,值爲要存放HTML的文件夾名稱 "static_path":"statics", #鍵爲static_path固定的,值爲要存放js和css的文件夾名稱 } #路由映射 application = tornado.web.Application([ #建立一個變量等於tornado.web下的Application方法 (r"/fwd", fwdHandler), ],**settings) #將html文件歸類配置字典,寫在路由映射的第二個參數裏 if __name__ == "__main__": #內部socket運行起來 application.listen(8001) #設置端口 tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script> </head> <body> <input type="button" value="跨域提交" onclick="doajax();"/> <script> function doajax() { //當點擊提交按鈕是執行函數 $.ajax({ type: 'GET', url: 'http://www.fwd.com:8001/fwd', dataType: 'jsonp', //JSONP,數據類型 jsonpCallBack:'shj' //接收響應頁面帶有參數的函數名稱 }); } //響應網站返回,shuju({'k1':'v1'}); 也就至關於返回了一個帶有參數的函數名稱 function shuju(shj) { //自定義執行函數,和響應網站返回的名稱相同,也就會執行自定義函數,而參數就是響應網站返回的數據 for (var i in shj) { //循環響應網站返回的數據 alert(i + ':' + shj[i]); //打印出數據的鍵和值 } } </script> </body>
響應端web
#!/usr/bin/env python #coding:utf-8 import tornado.ioloop import tornado.web #導入tornado模塊下的web文件 class fwdHandler(tornado.web.RequestHandler): def get(self): #接收get請求 # self.render("fwd.html") self.write("shuju({'k1':'v1'});") #返回數據 def post(self): self.write("post請求成功") settings = { #html文件歸類配置,設置一個字典 "template_path":"views", #鍵爲template_path固定的,值爲要存放HTML的文件夾名稱 "static_path":"statics", #鍵爲static_path固定的,值爲要存放js和css的文件夾名稱 } #路由映射 application = tornado.web.Application([ #建立一個變量等於tornado.web下的Application方法 (r"/fwd", fwdHandler), ],**settings) #將html文件歸類配置字典,寫在路由映射的第二個參數裏 if __name__ == "__main__": #內部socket運行起來 application.listen(8001) #設置端口 tornado.ioloop.IOLoop.instance().start()
簡單請求和非簡單請求的區別?
簡單請求:一次請求
非簡單請求:兩次請求,在發送數據以前會先發一次請求用於作「預檢」,只有「預檢」經過後纔再發送一次請求用於數據傳輸。ajax
條件:
一、請求方式:HEAD、GET、POST
二、請求頭信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 對應的值是如下三個中的任意一個
application/x-www-form-urlencoded
multipart/form-data
text/plain
注意:同時知足以上兩個條件時,則是簡單請求,不然爲複雜請求json
self.set_header()方法,在響應端的邏輯處理的get或者post裏使用,功能:給返回數據加上響應頭標識告訴瀏覽器容許跨域請求
使用方法:兩個參數,參數1,響應頭標識,參數2,容許跨域請求的域名(多個域名,號隔開),(*表明全部域名支持跨域請求)
self.set_header('Access-Control-Allow-Origin','http://www.jxiou.com/')
self.set_header('Access-Control-Allow-Origin','*')跨域
響應端
#!/usr/bin/env python #coding:utf-8 import tornado.ioloop import tornado.web #導入tornado模塊下的web文件 class fwdHandler(tornado.web.RequestHandler): def get(self): #接收get請求 pass def post(self): self.set_header('Access-Control-Allow-Origin','*') self.write("{'k1':'v1'}") # 返回數據 settings = { #html文件歸類配置,設置一個字典 "template_path":"views", #鍵爲template_path固定的,值爲要存放HTML的文件夾名稱 "static_path":"statics", #鍵爲static_path固定的,值爲要存放js和css的文件夾名稱 } #路由映射 application = tornado.web.Application([ #建立一個變量等於tornado.web下的Application方法 (r"/fwd", fwdHandler), ],**settings) #將html文件歸類配置字典,寫在路由映射的第二個參數裏 if __name__ == "__main__": #內部socket運行起來 application.listen(8001) #設置端口 tornado.ioloop.IOLoop.instance().start()
請求頁面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script> </head> <body> <input type="button" value="跨域提交" onclick="doajax();"/> <script> function doajax() { //當點擊提交按鈕是執行函數 $.ajax({ type: 'POST', url: 'http://www.fwd.com:8001/fwd', data: {"a":'b'}, success: function (response, status, xhr) { alert(response); //打印返回數據 } }); } </script> </body> </html>
複雜請求
複雜請求:兩次請求,在發送數據以前會先發一次OPTIONS請求用於作「預檢」,只有「預檢」經過後纔再發送一次請求用於數據傳輸。
self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") 預檢請求或者數據請求時容許跨域,容許跨域的域名(多個逗號隔開)(*標識全部域名容許)
self.set_header('Access-Control-Allow-Headers', "k1,k2") 預檢請求時容許請求頁面ajax設置請求頭headers屬性跨域,容許跨域的headers屬性請求頭(多個逗號隔開)
self.set_header('Access-Control-Allow-Methods', "PUT,DELETE") 預檢請求時容許請求頁面的請求方式跨域,容許跨域的請求方式(多個逗號隔開)
self.set_header('Access-Control-Max-Age', 10) 預檢請求時設置預檢有效時間,如設置10,表示此次預檢後10秒後的請求再次預檢
響應端
#!/usr/bin/env python #coding:utf-8 import tornado.ioloop import tornado.web #導入tornado模塊下的web文件 class fwdHandler(tornado.web.RequestHandler): def get(self): #接收get請求 pass def options(self): #接收預檢的options請求 self.set_header('Access-Control-Allow-Origin', '*') #預檢請求或者數據請求時容許跨域,容許跨域的域名(多個逗號隔開)(*標識全部域名容許) self.set_header('Access-Control-Allow-Methods', 'PUT') #預檢請求時容許請求頁面的請求方式跨域,容許跨域的請求方式(多個逗號隔開) self.set_header('Access-Control-Allow-Headers', "k1,k2") #預檢請求時容許請求頁面ajax設置請求頭headers屬性跨域,容許跨域的headers屬性請求頭(多個逗號隔開) def put(self): self.set_header('Access-Control-Allow-Origin','*') self.write("{'k1':'v1'}") # 返回數據 settings = { #html文件歸類配置,設置一個字典 "template_path":"views", #鍵爲template_path固定的,值爲要存放HTML的文件夾名稱 "static_path":"statics", #鍵爲static_path固定的,值爲要存放js和css的文件夾名稱 } #路由映射 application = tornado.web.Application([ #建立一個變量等於tornado.web下的Application方法 (r"/fwd", fwdHandler), ],**settings) #將html文件歸類配置字典,寫在路由映射的第二個參數裏 if __name__ == "__main__": #內部socket運行起來 application.listen(8001) #設置端口 tornado.ioloop.IOLoop.instance().start()
請求頁面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script> </head> <body> <input type="button" value="跨域提交" onclick="doajax();"/> <script> function doajax() { //當點擊提交按鈕是執行函數 $.ajax({ type: 'PUT', //複雜請求 url: 'http://www.fwd.com:8001/fwd', headers: {'k1': 'qqtou'}, //設置請求頭 data: {"a":'b'}, success: function (response, status, xhr) { alert(response); //打印返回數據 } }); } </script> </body> </html>
跨域傳輸cookie
在跨域請求中,默認狀況下,HTTP Authentication信息,Cookie頭以及用戶的SSL證書不管在預檢請求中或是在實際請求都是不會被髮送。
若是想要發送:
瀏覽器端ajax屬性:xhrFields的withCredentials爲true
服務器端的預檢請求和數據請求:Access-Control-Allow-Credentials爲true
注意:服務器端響應的 Access-Control-Allow-Origin 不能是通配符 *
響應端
/usr/bin/env python #coding:utf-8 import tornado.ioloop import tornado.web #導入tornado模塊下的web文件 class fwdHandler(tornado.web.RequestHandler): def get(self): #接收get請求 pass def options(self): #接收預檢的options請求 self.set_header('Access-Control-Allow-Credentials', "true") #傳遞Cookie頭以及用戶的SSL證書 self.set_header('Access-Control-Allow-Origin', 'http://www.khd.com:8002') #預檢請求或者數據請求時容許跨域,容許跨域的域名 self.set_header('Access-Control-Allow-Methods', 'PUT') #預檢請求時容許請求頁面的請求方式跨域,容許跨域的請求方式(多個逗號隔開) self.set_header('Access-Control-Allow-Headers', "k1,k2") #預檢請求時容許請求頁面ajax設置請求頭headers屬性跨域,容許跨域的headers屬性請求頭(多個逗號隔開) def put(self): self.set_header('Access-Control-Allow-Credentials', "true") # 傳遞Cookie頭以及用戶的SSL證書 self.set_header('Access-Control-Allow-Origin','http://www.khd.com:8002') self.write("{'k1':'v1'}") # 返回數據 self.set_cookie('kkkkk', 'vvvvv') #寫入cookie print(self.get_cookie('kkkkk')) #獲取cookie settings = { #html文件歸類配置,設置一個字典 "template_path":"views", #鍵爲template_path固定的,值爲要存放HTML的文件夾名稱 "static_path":"statics", #鍵爲static_path固定的,值爲要存放js和css的文件夾名稱 } #路由映射 application = tornado.web.Application([ #建立一個變量等於tornado.web下的Application方法 (r"/fwd", fwdHandler), ],**settings) #將html文件歸類配置字典,寫在路由映射的第二個參數裏 if __name__ == "__main__": #內部socket運行起來 application.listen(8001) #設置端口 tornado.ioloop.IOLoop.instance().start()
請求頁面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" src='{{static_url("jquery.min.js")}}' charset="UTF-8"></script> </head> <body> <input type="button" value="跨域提交" onclick="doajax();"/> <script> function doajax() { //當點擊提交按鈕是執行函數 $.ajax({ type: 'PUT', //複雜請求 url: 'http://www.fwd.com:8001/fwd', headers: {'k1': 'qqtou'}, //設置請求頭 xhrFields:{withCredentials: true}, //傳遞Cookie頭以及用戶的SSL證書 data: {"a":'b'}, success: function (response, status, xhr) { alert(response); //打印返回數據 } }); } </script> </body> </html>
self.set_header('xxoo', "bili") 設置響應頭第一個是響應頭名稱,第二個是響應頭值
self.set_header('Access-Control-Expose-Headers', "xxoo,bili") 容許設置的響應頭,請求端獲取
#!/usr/bin/env python #coding:utf-8 import tornado.ioloop import tornado.web #導入tornado模塊下的web文件 class fwdHandler(tornado.web.RequestHandler): def get(self): #接收get請求 pass def options(self): #接收預檢的options請求 self.set_header('Access-Control-Allow-Credentials', "true") #傳遞Cookie頭以及用戶的SSL證書 self.set_header('Access-Control-Allow-Origin', 'http://www.khd.com:8002') #預檢請求或者數據請求時容許跨域,容許跨域的域名 self.set_header('Access-Control-Allow-Methods', 'PUT') #預檢請求時容許請求頁面的請求方式跨域,容許跨域的請求方式(多個逗號隔開) self.set_header('Access-Control-Allow-Headers', "k1,k2") #預檢請求時容許請求頁面ajax設置請求頭headers屬性跨域,容許跨域的headers屬性請求頭(多個逗號隔開) def put(self): self.set_header('Access-Control-Allow-Credentials', "true") # 傳遞Cookie頭以及用戶的SSL證書 self.set_header('Access-Control-Allow-Origin','http://www.khd.com:8002') self.set_header('xxoo', "bili") #設置響應頭第一個是響應頭名稱,第二個是響應頭值 self.set_header('Access-Control-Expose-Headers', "xxoo,bili") #容許設置的響應頭,請求端獲取 self.write("{'k1':'v1'}") # 返回數據 self.set_cookie('kkkkk', 'vvvvv') #寫入cookie print(self.get_cookie('kkkkk')) #獲取cookie settings = { #html文件歸類配置,設置一個字典 "template_path":"views", #鍵爲template_path固定的,值爲要存放HTML的文件夾名稱 "static_path":"statics", #鍵爲static_path固定的,值爲要存放js和css的文件夾名稱 } #路由映射 application = tornado.web.Application([ #建立一個變量等於tornado.web下的Application方法 (r"/fwd", fwdHandler), ],**settings) #將html文件歸類配置字典,寫在路由映射的第二個參數裏 if __name__ == "__main__": #內部socket運行起來 application.listen(8001) #設置端口 tornado.ioloop.IOLoop.instance().start()