摘要:同源策略是處于對用戶安全的考慮,如果非同源就會受到以下限制不能讀取無法獲得請求不能發送但是事實是經常需要借助非同源來提供數據,所以就需要進行跨域請求。
什么是跨域
注:本文完整示例地址
先來說一個概念就是同源,同源指的是協議,端口,域名全部相同。
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
同源策略是處于對用戶安全的考慮,如果非同源就會受到以下限制:
cookie不能讀取
dom無法獲得
ajax請求不能發送
但是事實是經常需要借助非同源來提供數據,所以就需要進行跨域請求。
JSONPJSONP是指JSON Padding,JSONP是一種非官方跨域數據交換協議,由于script的src屬性可以跨域請求,所以JSONP利用的就是瀏覽器的這個“漏洞”,需要通信時,動態的插入一個script標簽。請求的地址一般帶有一個callback參數,假設需要請求的地址為http://localhost:666?callback=show,服務端返回的代碼一般是show(數據)的JSON數據,而show函數恰恰是前臺需要用這個數據的函數。JSONP非常的簡單易用,自動補全API利用的就是JSONP,下面來看一個例子:
// 前端請求代碼 function jsonp (callback) { var script = document.createElement("script"), url = `http://localhost:666?callback=${callback}`; script.setAttribute("src", url); document.querySelector("head").appendChild(script); } function show (data) { console.log(`學生姓名為:${data.name},年齡為:${data.age},性別為${data.sex}`); } jsonp("show"); // 后端響應代碼 const student = { name: "zp1996", age: 20, sex: "male" }; var callback = url.parse(req.url, true).query.callback; res.writeHead(200, { "Content-Type": "application/json;charset=utf-8" }); res.end(`${callback}(${JSON.stringify(student)})`);
JSONP雖說簡單易用,但是有一個很大問題,那就是JSONP只能進行get請求
CORSCORS(跨域資源共享)是由W3C制定的跨站資源分享標準,可以讓AJAX實現跨域訪問。想要了解跨域的話,首先需要了解下簡單請求:
請求方式為GET或者POST
假若請求是POST的話,Content-Type必須為下列之一:
application/x-www-form-urlencoded
multipart/form-data
text/plain
不含有自定義頭(類似于segmentfault自定義的頭X-Hit)
對于簡單請求的跨域只需要進行一次http請求:
function ajaxPost (url, obj, header) { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(), str = "", keys = Object.keys(obj); for (var i = 0, len = keys.length; i < len; i++) { str += `${keys[i]}=${obj[keys[i]]}&`; } str = str.substring(0, str.length - 1); xhr.open("post", url); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); if (header instanceof Object) { for (var k in header) xhr.setRequestHeader(k, header[k]); } xhr.send(str); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { resolve(xhr.responseText); } else { reject(); } } } }); } ajaxPost("http://localhost:666?page=cors", { name: "zp1996", age: 20, sex: "male" }) .then((text) => { console.log(text); }, () => { console.log("請求失敗"); }); // 后端處理 var postData = ""; // 注釋下,下面示例后臺代碼補充在此處 req.on("data", (data) => { postData += data; }); req.on("end", () => { postData = querystring.parse(postData); res.writeHead(200, { "Access-Control-Allow-Origin": "*", "Content-Type": "application/json;charset=utf-8" }); if (postData.name === student.name && Number(postData.age) === student.age && postData.sex === student.sex ) { res.end(`yeah!${postData.name} is a good boy~`); } else { res.end("No!a bad boy~"); } });
打開控制臺觀察可以發現,Network只是發出了一次請求,但是對于非簡單請求來說,需要兩次http請求,在真正的請求之前需要進行一次預請求,下圖是進行一次預請求的請求/響應:
觀察響應頭,可以發現需要多出了兩個響應頭:
Access-Control-Allow-Headers,用來指明在實際的請求中,可以使用那些自定義的http請求頭。
Access-Control-Max-Age,用來指定此次預請求的結果的有效期,在有效期內則不會發出預請求,有點像緩存的感覺。
當然還有諸如好多這樣的響應頭,請大家自行搜索了解,這里就不再過多介紹,下面來看下對于非簡單請求跨域的代碼處理:
// 前端請求代碼 ajaxPost("http://localhost:666?page=cors", { name: "zp1996", age: 20, sex: "male" }, { "X-author": "zp1996" }) .then((text) => { console.log(text); }, () => { console.log("請求失敗"); }); // 后端處理,補充在簡單請求代碼注釋處 if (req.method === "OPTIONS") { res.writeHead(200, { "Access-Control-Max-Age": 3000, "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "X-author", "Content-Type": "application/json;charset=utf-8" }); res.end(); return void 0; }CSS Text Transformation
既然可以利用script的“漏洞”來進行JSONP跨域,那么是不是也可以利用css樣式寫可以進行跨域請求來進行跨域呢?答案肯定是yes,利用css還有一個好處那就是,當被注入攻擊腳本時,css盡管被注入,也不會引起什么大的安全問題,頂多也就是把頁面的樣式給改變,而js被注入的話,cookie就有可能被盜取等一系列安全問題出現。大牛已經將其做的非常完善,大家可以去star王集鵠(zswang)CSST,這里我就把我所理解給大家簡單的分享下:
// 前端代碼 const id = "csst", ele = document.querySelector(`#${id}`), head = document.querySelector("head"); function getStyle (ele, prop) { return getComputedStyle(ele, "").getPropertyValue(prop); } function loadCss (url) { return new Promise((resolve) => { const link = document.createElement("link"); link.setAttribute("rel", "stylesheet"); link.setAttribute("type", "text/css"); link.setAttribute("href", url); ele.addEventListener("webkitAnimationStart", function () { resolve(getStyle(ele, "content")); }); head.appendChild(link); }); } loadCss(`http://localhost:666?page=data.css&id=${id}`).then((data) => { console.log(data); }); // 后端代碼 function cssData (id) { return ` @keyframes a{ from{ } to{ color: red; } } #${id} { content: "這種是很好,但是只能傳輸文本啊"; animation: a 2s; } `; } res.writeHead(200, { "Content-Type": "text/css" }); res.end(cssData(query.id));
通過代碼可以看出這種實現方式是靠元素的content來拿接收到的數據,所以傳輸的只能是文本。至于為什么要返回動畫?是因為不利用動畫,無法來對css腳本加載進行監測,也就無法進行回調(由于谷歌/火狐不支持link的onload和onreadychange,所以利用animationstart事件)。
window.postMessagewindow.postMessage 是一個安全的跨源通信的方法。一般情況下,當且僅當執行腳本的頁面使用相同的協議(通常都是 http)、相同的端口(http默認使用80端口)和相同的 host(兩個頁面的 document.domain 的值相同)時,才允許不同頁面上的腳本互相訪問。 window.postMessage 提供了一個可控的機制來安全地繞過這一限制,當其在正確使用的情況下。
window.postMessage解決的不是瀏覽器與服務器之間的交互,解決的是瀏覽器不同的窗口之間的通信問題,可以做的就是同步兩個網頁,當然這兩個網頁應該是屬于同一個基礎域名。
// 發送端代碼 var domain = "http://localhost", index = 1, target = window.open(`${domain}/postmessage-target.html`); function send () { setInterval(() => { target.postMessage(`第${index++}次數據發送`, domain); }, 1000); } send(); // 接受端代碼沒有數據過來啊上述代碼實現了向一個頁面向另一個發送數據,但是這么寫往往有著一些“危險”,需要知道的是,postMessage是向document對象中,網絡連接有時會很慢,可能會出現些問題,所以最好的方式是接受頁面已經開始加載了,這時發送一個消息給發送端,發送端在開始向接收端發送數據。改進下:
// 發送端添加代碼 window.addEventListener("message", (e) => { if (e.data === "ok") send(); else console.log(e.data); }); // 接受端的head里面加上script標簽window.namewindow.name 的美妙之處:name 值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的 name 值(2MB)
這個方式我基本上沒有用過,所以沒有過多的發言權,大家想了解這個技術的話,可以通過懌飛(圓心):使用 window.name 解決跨域問題,圓心大神解釋的非常透徹。
document.domain將子域和主域的document.domain設為同一個主域
前提條件:這兩個域名必須屬于同一個基礎域名
而且所用的協議,端口都要一致,否則無法利用document.domain進行跨域
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/91077.html
相關文章
XMLHTTPRequest屬性、方法、事件大全&詳解。
摘要:屬性方法事件整理大全。有嚴格安全限制。值描述將設為空字符串與設置為相同,是默認類型實際上是。默認值為空字符串只有當為時,對象上才有此屬性,此時才能調用,否則拋錯。以下種情況下值都為空字符串請求未完成請求失敗。 XMLHTTPRequest屬性、方法、事件整理大全。 xhr 對象的方法 open(method:string, url:string, async?:boolean=tr...
【收藏干貨】axios配置大全
摘要:一安裝利用安裝利用安裝直接利用引入二例子發送一個請求通過給定的來發送請求以上請求也可以通過這種方式來發送發送一個請求一次性并發多個請求當這兩個請求都完成的時候會觸發這個函數,兩個參數分別代表返回的結果三的可以通過配置來發送請求發送一 一、安裝 1、 利用npm安裝npm install axios --save 2、 利用bower安裝bower install axios --sav...
前端基礎入門
摘要:手把手教你做個人火的時候,隨便一個都能賺的盆滿缽滿,但是,個人沒有服務端,沒有美工,似乎就不能開發了,真的是這樣的嗎秘密花園經典的中文手冊。涵蓋前端知識體系知識結構圖書推薦以及入門視頻教程,全的簡直不要不要的了。 JavaScript 實現點擊按鈕復制指定區域文本 html5 的 webAPI 接口可以很輕松的使用短短的幾行代碼就實現點擊按鈕復制區域文本的功能,不需要依賴 flash。...
前端最實用書簽(持續更新)
摘要:前言一直混跡社區突然發現自己收藏了不少好文但是管理起來有點混亂所以將前端主流技術做了一個書簽整理不求最多最全但求最實用。 前言 一直混跡社區,突然發現自己收藏了不少好文但是管理起來有點混亂; 所以將前端主流技術做了一個書簽整理,不求最多最全,但求最實用。 書簽源碼 書簽導入瀏覽器效果截圖showImg(https://segmentfault.com/img/bVbg41b?w=107...
【回顧九月份第二周】 前端你該知道的事兒
摘要:順便一說,這首歌的原唱是秋田,中島當年嗓子壞了,才有這歌。中文是直接翻譯來的,作曲是秋田。一部電影春夏秋冬又一春春夏秋冬又一春是由金基德執導,金英民吳英秀金基德主演的一部韓國電影。年月日于韓國上映。 原鏈接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...
發表評論
0條評論
閱讀 1989·2021-11-22 19:20
閱讀 2631·2021-11-22 13:54
閱讀 1956·2021-09-04 16:40
閱讀 1822·2021-08-13 11:54
閱讀 2654·2019-08-30 15:55
閱讀 3464·2019-08-29 13:51
閱讀 527·2019-08-29 11:09
閱讀 3007·2019-08-26 14:06