摘要:瀏覽器同源策略什么是瀏覽器同源策略同源策略是瀏覽器安全的基礎。同源策略限制從一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這里我們做一下簡要的總結受到瀏覽器同源策略的限制,頁面的無法被頁面的訪問和操作。不受同源策略的限制。
瀏覽器同源策略 什么是瀏覽器同源策略?
“同源策略”(Same Origin Policy)是瀏覽器安全的基礎。
同源策略限制從一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用于隔離潛在惡意文件的關鍵的安全機制。
在判斷兩個頁面的url是否具有相同的源之前,我們先來看一下一個url(統一資源定位符)的基本組成部分。
對于一個url,它的基本組成部分是:協議 :// 域名(或者是ip) : 端口(如果指定了) / 路徑。
那么下面我們來舉個例子:
對于http://www.example.com/static來說,協議就是http,它的域名是www.example.com,它的路徑是static,這里的端口號省略了(默認為80)。
值得一提的是,在這個域名下面,example.com是主域名,而www.example.com是子域名,同樣的a.example.com也是一個與前面所述不同的另一個子域名。并且,上面這三個域名互不相同。
這里不再展開贅述,相關知識請查閱與計算機網絡有關的知識。
那如何判斷頁面是否具有相同的源呢?
如果協議,端口(如果指定了)和域名對于兩個頁面是相同的,則兩個頁面具有相同的源。
也就是說,判斷同源的三要素是:協議、端口、域名。
需要注意的是,如果是一個域名二級域名,比如上面提到的www.example.com,它與另外一個二級域名a.example.com,雖然他們的主域相同,但是子域不同,于是這兩個就不是同一個域名,所以也不能說是同源。三級域名依次類推...
下表給出了相對http://store.company.com/dir/page.html同源檢測的示例:
關于Cookie和Session說到同源策略,必不可少的就是Cookie這個東西了。
而講到Cookie,跟它關聯在一起的又有Session。
對于這兩者,這里不做大篇幅的介紹,具體去傳送門查閱。
這里我們做一下簡要的總結:
Cookie受到瀏覽器同源策略的限制,A頁面的Cookie無法被B頁面的Cookie訪問和操作。
Cookie最大存儲容量一般為4KB,由服務器生成,在HTTP報文首部設置Set-Cookie可以指定生成Cookie的內容和生命周期,如果由瀏覽器生成則在關掉瀏覽器后失效。
Cookie存儲在瀏覽器端,由于每次發送HTTP請求默認會把Cookie附到HTTP首部上去,所以Cookie主要用來身份認證,而不用來存儲其他信息,防止HTTP報文過大。
Session存儲在服務器,主要與Cookie配合使用完成身份認證和狀態保持的功能。只有Cookie或只有Session都無法完成身份認證和狀態保持的功能。
最后,對Cookie和Session實現的身份認證和狀態保持功能做一個舉例。
假設現在有一個學生信息管理系統,此時數據庫已經有學生的相關信息。(賬號、密碼、個人信息等等)
然后當學生登錄這個系統,通過POST請求把用戶的賬戶密碼發送到后臺服務器。當后臺服務器接收到這些參數的時候,會跟數據庫保存的記錄進行匹配。
一旦匹配成功,也就是用戶的賬號密碼都正確的情況下,這個時候后臺服務器會在Session中記錄一個值,可以是用戶名或者其他能夠唯一標識用戶的字段。
當把這個值保存在Session中后,后臺服務器會返回響應告知客戶端登錄成功,可以進行后續的操作。此時,后臺服務器會在HTTP響應報文中添加一個字段Set-Cookie,它的值是當前Session的SessionID,(這個SessionID是指向我們當前的那個Session的,在Node的Express中express-session會封裝好這個過程)當然還會設置Cookie的其他屬性,比如說過期時間Expires等等。
當瀏覽器接收到這個HTTP響應報文的時候,就會在本地設置一個Cookie,它的過期時間由響應報文中Set-Cookie中的Expires字段的值決定,如果為空,則關閉瀏覽器(即會話結束時)后失效。
之后,每次向后臺服務器發送請求的時候,瀏覽器默認會把這個Cookie加在HTTP請求報文的Cookie中。這樣,每次后臺服務器接收到請求的時候,會根據Cookie中的SessionID去找到我們的Session。
假如這個SessionID映射得到Session,那么這個時候說明瀏覽器是已經登錄過了。于是,就可以進行后續的一些相關的操作。
另外,值得一提的是,Session機制決定了當前客戶只會獲取到自己的Session,而不會獲取到別人的Session。各客戶的Session也彼此獨立,互不可見。也就是說,當多個客戶端執行程序時,服務器會保存多個客戶端的Session。獲取Session的時候也不需要聲明獲取誰的Session。
這就是Cookie和Session做狀態保持和身份驗證的一個具體的例子。
關于iframe說到同源限制,還有一個不得不提的就是iframe。
iframe可以在父頁面中嵌入一個子頁面,在日常開發中一旦使用,避免不了的就要涉及到不同的iframe頁面進行通信的問題,可能是獲得其他iframe的DOM,或者是獲取其他iframe上的全局變量或方法等等。
同源下的iframe,也就是iframe中的src屬性的URL符合同源的條件,那么通過iframe的contentDocument和contentWindow獲取其他iframe的DOM或者全局變量、方法都是很簡單的事情。
那如果是非同源的兩個iframe,單純的通過變量訪問的方式就受到同源限制了。
為了解決這個問題,HTML5引入了一個新的API:postMessage,主要就是用來解決存在跨域問題的iframe頁面之間通信的問題。
下面簡單的舉一個例子,假如現在有兩個不同的頁面,A頁面的url是http://localhost:4002/parent.html,B頁面的url的是http://localhost:4003/child.html,現在我把B頁面用iframe嵌在A頁面下面,代碼(精簡)是這樣子的。現在我要實現的是向子頁面B傳遞一個消息:
A頁面代碼:
A頁面
B頁面代碼:
B頁面
結果如圖:
postMessage接受兩個參數,一個是要傳送的data,另外一個是目標窗口的源,如果想傳給任何窗口,可以設置成*。
目標頁面接收信息的時候,使用的是window.addEventListener("message", function() {})。
當然也有不受同源限制的情況存在,主要有以下列舉的:
script標簽允許跨域嵌入腳本,稍后介紹的JSONP就是利用這個“漏洞”來實現。
img標簽、link標簽、@font-face不受跨域影響。
video和audio嵌入的資源。
iframe載入的任何資源。(不是iframe之間的通信)
、和的插件。
WebSocket不受同源策略的限制。
開發時常用解決方案 CORS——跨域資源共享注:以下跨域資源共享的兩種請求辨析內容摘抄至阮一峰的《跨域資源共享》一文。
什么是跨域資源共享?CORS是一個W3C標準,全稱是“跨域資源共享”(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務器發出XMLHttpRequest請求,從而克服了AJAX只能同源發送請求的限制。
實現CORS主要在于服務器的設置,關鍵在于服務器HTTP響應報文首部的設置。前端部分大致還是跟原來發AJAX請求沒什么區別,只是需要對AJAX進行一些相關的設置,稍后我們都會講到。
CORS的兩種請求在講解如何實現跨域資源共享的時候,我們先來看一下CORS的兩種請求。
瀏覽器將CORS分為兩種請求,一種是簡單請求,另外一種對應的肯定就是非簡單請求。
只要同時滿足下面兩大條件,就屬于簡單請求:
請求的方法是一下的三種方法之一:
HEAD
GET
POST
HTTP的頭信息不超過以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type: 只限于三個值:application/x-www-form-urlencoded、multipart/formdata、text/plain。
凡是不同時滿足以上兩種條件,就屬于非簡單請求。
瀏覽器對于兩種請求處理是不一樣的。
簡單請求對于簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在HTTP請求報文首部,增加一個Origin字段。如下:
GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
上面Origin字段的用來說明本次請求來自哪個源(協議+域名+端口)。服務器根據這個值,決定是否同意這次請求。
如果Origin指定的源,不在許可范圍內,服務器會返回一個正常的HTTP回應。瀏覽器發現,這個回應的頭信息沒有包含Access-Control-Allow-Origin字段(詳見下文),就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。注意,這種錯誤無法通過狀態碼識別,因為HTTP回應的狀態碼有可能是200。
如果Origin指定的域名在許可范圍內,服務器返回的響應,會多出幾個頭信息字段。
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
上面的HTTP響應報文首部信息中,有三個與CORS請求相關的字段,都是以Access-Control-開頭。
Access-Control-Allow-Origin
該字段是必須的,它的值要么是請求Origin字段,要么是一個*,表示接受任意域名的請求。
Access-Control-Allow-Credentials
該字段可選。它的值是一個布爾值,表示是否允許發送Cookie。默認情況下,Cookie不包括在CORS請求之中。設為true,即表示服務器明確許可,Cookie可以包含在請求中,一起發給服務器。這個值也只能設為true,如果服務器不要瀏覽器發送Cookie,刪除該字段即可。
值得一提的是,如果想要CORS支持Cookie,不僅要在服務器指定HTTP響應報文首部字段,還需要在AJAX中打開withCredentials的屬性。(jQuery中AJAX設置后面會講到)
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
有些瀏覽器在省略withCredentials設置的時候,還是會發送Cookie。于是,可以顯式關閉這個屬性。
xhr.withCredentials = false;
需要注意的是,如果要發送Cookie,Acess-Control-Allow-Origin不能設置為*,必須設置成具體的域名,如果是本地調試的話可以考慮設置成null。
Access-Control-Expose-Headers
該字段可選。CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader("FooBar")可以返回FooBar字段的值。
非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。
非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。
瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。
下面是一段JavaScript腳本:
var url = "http://api.alice.com/cors"; var xhr = new XMLHttpRequest(); xhr.open("PUT", url, true); xhr.setRequestHeader("X-Custom-Header", "value"); xhr.send();
很明顯,這是一個非簡單請求,使用了PUT方法來發送請求,并且自定義了一個HTTP請求報文的首部字段。
于是,瀏覽器發現這是一個非簡單的請求,就自動發出了一個“預檢”請求,要求服務器確認可以這樣請求。下面是這個“預檢”請求的HTTP頭信息。
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
"預檢"請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。頭信息里面,關鍵字段是Origin,表示請求來自哪個源。
除了Origin字段,“預檢”請求的頭信息還包括兩個特殊字段。
Access-Control-Request-Method
該字段是必須的,用來列出瀏覽器的CORS會用到哪些HTTP方法,上面是PUT。
Access-Control-Request-Headers
該字段是一個用逗號分隔的字符串,指定瀏覽器CORS請求會額外發送的頭信息。上面的例子是X-Custom-Header。
于是,服務器收到“預檢”請求之后,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認允許跨域請求,就可以做出回應。
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
如果瀏覽器否定了"預檢"請求,會返回一個正常的HTTP回應,但是沒有任何CORS相關的頭信息字段。這時,瀏覽器就會認定,服務器不同意預檢請求,因此觸發一個錯誤,被XMLHttpRequest對象的onerror回調函數捕獲。控制臺會打印出如下的報錯信息。
XMLHttpRequest cannot load http://api.alice.com. Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.
服務器回應的其他CORS相關字段如下:
Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Access-Control-Allow-Credentials: true Access-Control-Max-Age: 1728000
對比簡單請求服務器響應的CORS字段,發現多了三個:
Access-Control-Allow-Methods
該字段必需,它的值是逗號分隔的一個字符串,表明服務器支持的所有跨域請求的方法。注意,返回的是所有支持的方法,而不單是瀏覽器請求的那個方法。這是為了避免多次"預檢"請求。
Access-Control-Allow-Headers
如果瀏覽器請求包括Access-Control-Request-Headers字段,則Access-Control-Allow-Headers字段是必需的。它也是一個逗號分隔的字符串,表明服務器支持的所有頭信息字段,不限于瀏覽器在"預檢"中請求的字段。
Access-Control-Max-Age
該字段可選,用來指定本次預檢請求的有效期,單位為秒。上面結果中,有效期是20天(1728000秒),即允許緩存該條回應1728000秒(即20天),在此期間,不用發出另一條預檢請求。
于是,一旦瀏覽器通過了“預檢”,以后每次瀏覽器正常的CORS請求,都跟簡單請求一樣,會有一個Origin頭信息字段。服務器的回應,也都有一個Access-Control-Allow-Origin頭信息字段。如果開啟了Cookie設置,那還有一個Access-Control-Allow-Credentials:true。
如何在Node實現跨域資源共享?那怎么在Node中結合Express設置后臺的跨域部分呢?
其實很簡單,需要設置的就是上面所述的幾個響應首部的字段,主要考慮兩種類型的請求和是否需要使用Cookie。具體設置如下:
app.all("*", function(req, res, next) { res.header("Access-Control-Allow-Origin", /* url | * | null */); res.header("Access-Control-Allow-Headers", "Authorization, X-Requested-With"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); /* 服務器支持的所有字段 */ res.header("Access-Control-Allow-Credentials", "true"); /* 當使用Cookie時 */ res.header("Access-Control-Max-Age", 300000); /* 設置預檢請求的有效期 */ if (req.method === "OPTIONS") return res.send(200); /*讓options請求快速返回*/ else next(); });
上面的設置有幾個需要注意的地方:
如果需要本地調試,也就是在本地HTML頁面發請求(類似file://...之類的url),可以把Access-Control-Allwo-Origin的值設置為Null,這樣子就能夠使用Cookie。如果設置成*,雖然也可以跨域發送請求,但是這個時候沒有辦法使用Cookie。
Access-Control-Allow-Headers字段不是必須的,僅當發送的請求有Access-Control-Request-Headers時需要設置。
使用Cookie的時候要配置Access-Control-Allow-Methods字段。
“預檢”請求可設置緩存時間,可以保證不多次發送“預檢”請求。
需要判斷是否為“預檢”請求,當攔截“預檢”請求的時候直接返回。
如果使用jQuery封裝的AJAX發送請求,那么需要在相應的JS代碼設置:
$.ajaxSetup({ xhrFields: { withCredentials: true }, crossDomain: true });
withCredentials是設置CORS發送Cookie,默認是不發送的。
crossDomain告知AJAX允許跨域。
以上就是CORS設置跨域的具體介紹。
基于JSONP技術實現跨域 JSONP原理對于JSONP來說,前面也已經提到了,其實它是利用了某些不受同源限制的標簽的所謂“漏洞”,來實現“曲線救國”式的跨域的方案。
它借用script標簽不受同源限制的這個特性,通過動態的給頁面添加一個script標簽,利用事先聲明好的數據處理函數來獲取數據。
值得一提的是,JSONP這種方法其實和CORS有很大的區別,它并不屬于一種規范。所謂的JSONP是應用JSON數據的一種新方法,它只不過是被包含在函數調用中的JSON。
在JSONP中包含兩部分:回調函數和數據。其中,回調函數是當響應到來時要放在當前頁面被調用的函數。而數據,就是傳入回調函數中的JSON字符串,也就是回調函數的參數了。下面我們簡單模擬一下JSONP的通信過程。
JSONP的原理詳細講解可以看這個傳送門。
我們來簡單的模擬一下JSONP的通信過程。
function handleResponse(response) { console.log(response.data); } var script = document.createElement("script"); script.src = "http://example.com/jsonp/getSomething?uid=123&callback=hadleResponse" document.body.insertBefore(script, document.body.firstChild); /*handleResponse({"data": "hey"})*/
它的過程是這樣子的:
當我們通過新建一個script標簽請求時,后臺會根據相應的參數來生成相應的JSON數據。比如說上面這個鏈接,傳遞了handleResponse給后臺,然后后臺根據這個參數再結合數據生成了handleResponse({"data": "hey"})。
緊接著,這個返回的JSON數據其實就可以被當成一個js腳本,就是對一個函數的調用。
由于我們事先已經聲明了這么一個回調函數,于是當資源加載進來的時候,直接就對函數進行調用,于是數據當然就能獲取到了。
至此,跨域通信完成。
另外,想要實現JSONP,后臺服務器也必須做相應的設置。
值得一提的是,JSONP是存在一定的局限性的:
只能用于GET請求
存在安全問題,請求代碼中可能存在安全隱患
要確定JSONP請求是否失敗并不容易
一個簡單的JSONP實現下面是一個實現JSONP的庫,我們來一起分析一下它的源代碼。這是源碼的github地址。
/** * Module dependencies */ var debug = require("debug")("jsonp"); //使用依賴 /** * Module exports. */ module.exports = jsonp; //輸出模塊 /** * Callback index. */ var count = 0; //回調函數的index值,便于取名。 /** * Noop function. */ function noop(){} //無操作空函數,以便使用后把window[id]置空 /** * JSONP handler * * Options: * - param {String} qs parameter (`callback`) * - prefix {String} qs parameter (`__jp`) * - name {String} qs parameter (`prefix` + incr) * - timeout {Number} how long after a timeout error is emitted (`60000`) * * @param {String} url * @param {Object|Function} optional options / callback //這里的callback是取得數據后的callback,不是傳給服務器的callback * @param {Function} optional callback */ function jsonp(url, opts, fn){ if ("function" == typeof opts) { fn = opts; opts = {}; } if (!opts) opts = {}; var prefix = opts.prefix || "__jp"; // use the callback name that was passed if one was provided. // otherwise generate a unique name by incrementing our counter. var id = opts.name || (prefix + (count++)); var param = opts.param || "callback"; var timeout = null != opts.timeout ? opts.timeout : 60000; var enc = encodeURIComponent; var target = document.getElementsByTagName("script")[0] || document.head; var script; var timer; //一定時間內后臺服務器沒有返回視為超時 if (timeout) { timer = setTimeout(function(){ cleanup(); if (fn) fn(new Error("Timeout")); }, timeout); } //回復原始設置、清空狀態 function cleanup(){ if (script.parentNode) script.parentNode.removeChild(script); window[id] = noop; if (timer) clearTimeout(timer); } //取消操作 function cancel(){ if (window[id]) { cleanup(); } } //聲明函數,等待script標簽加載的url引入完畢后調用 window[id] = function(data){ debug("jsonp got", data); cleanup(); if (fn) fn(null, data);//node中約定第一個參數為err,但是這里不傳,直接就置為null }; // add qs component url += (~url.indexOf("?") ? "&" : "?") + param + "=" + enc(id); url = url.replace("?&", "?"); debug("jsonp req "%s"", url); // create script script = document.createElement("script"); script.src = url; target.parentNode.insertBefore(script, target); //引入script標簽后會直接去調用聲明的函數,然后函數會把script標簽帶有的data給傳出去 return cancel; //返回初始狀態 }基于JSONP庫的封裝
接著,我們可以利用上面的這個庫,給它進行一個封裝,下面是我們自己寫的_jsonp函數:
/* 這個是自己定義的一個_jsonp */ /** * @param {String} url * @param {Object} data * @param {Object} option * @returns */ function _jsonp(url, data, option) { url += (url.indexOf("?") < 0 ? "?" : "&") + param(data); return new Promise((resolve, reject) => { jsonp(url, option, (err, data) => { if (!err) { resolve(data); } else { reject(err); } }); }); /* 這里把jsonp封裝成了一個promise對象,回調函數中如果成功的話會把數據帶回來然后resolve出去 */ } //緊接著是對參數的一個序列化 function param(data) { let url = ""; for (var k in data) { let value = data[k] !== undefined ? data[k] : ""; url += `&${k}=${encodeURIComponent(value)}`; } return url ? url.substring(1) : "";/* 這里的substring保證不會有多余的& */ }在jQuery中使用JSONP
另外,在jQuery中的AJAX中,已經封裝了JSONP,下面簡單介紹一下如何去使用。
$.ajax({ type: "get", url: "http://example.com", dataType: "jsonp", jsonp: "callback", jsonpCallback: "responseCallback", success: function (data) { console.log(data); }, error: function (data) { console.log(data); } });
在AJAX中,主要設置dataType類型為jsonp。對于jsonp參數來說,默認值是callback,而jsonpCallback參數的值默認是jQuery自己生成的。如果想自己指定一個回調函數,可像代碼中對jsonpCallback進行設置。上面的代碼中,最終的url將會是http://example.com?callback=responseCallback。
使用代理服務器轉發請求由于同源策略僅存在于瀏覽器。對于服務器與服務器之間的通訊,是不存在任何同源限制的說法的。
因此,使用代理服務器來轉發請求也是我們在日常開發中解決跨域的一個常用的手段。
實現的方法很簡單,只要你會使用Node和Express。
需要注意的是,通常后臺服務器都會自己的一個驗證的機制,比如說微信文章在iframe中圖片是加載不出來的,因為其后臺對referer進行了驗證。另外,有些服務器也會通過發送一些uid等等之類的字符串供后臺校驗。因此,我們在使用代理服務器的時候,要重點關注請求的參數,這樣才能準確的模擬出請求并轉發。
下面簡單介紹如何使用代理服務器轉發請求。
分析url請求所需要的參數。
代理服務器暴露出一個api,這個路由實際的功能是去請求真正的服務器。
之后,我們只要請求這個api,我們所建的代理服務器就會默認的幫我們去轉發請求到真正的服務器上,其中會加上一些相應的參數。
最后,我們來利用反微信圖片防盜鏈這個實例來寫一個代理服務器。
如何使用代理服務器反微信圖片防盜鏈?當我們上線了一個網站的時候,然后img標簽引用了微信圖片的地址,會出現下面的這種情況。
這就是所謂的防盜鏈。
現在我們給它加上一個代理,代碼如下:
var express = require("express"); var superagent = require("superagent"); var app = express(); app.use("/static", express.static("public")); app.get("/getwxImg", (req, res) => { //如果單純的去獲取會出現參數丟失的情況,因為出現了兩個問號 var url = req.url.substring(req.url.indexOf("param=") + 6); res.writeHead(200, { "Content-Type": "image/*" }); superagent.get(url) .set("Referer", "") .set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36" ) .end(function (err, result) { if (err) { return false; } res.end(result.body); return; }); }); app.listen(4001, (err) => { if (err) { console.log(err); } else { console.log("server run!"); } });
這樣子,我們就可以把鏈接修改成我們服務器的地址,然后把真正的url作為我們的參數。
結果如下:
結果顯而易見,這就是所謂的代理服務器,附上github項目地址。
參考鏈接:
瀏覽器同源策略:https://developer.mozilla.org...
Cookie與Session:http://www.cnblogs.com/linguo...
CORS跨域資源共享:http://www.ruanyifeng.com/blo...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/90146.html
摘要:在接觸前端開發起,跨域這個詞就一直以很高的頻率在我們學習工作中重復出現,最近在工作中遇到了跨域的相關問題,這里我把它總結記錄一下。 在接觸前端開發起,跨域這個詞就一直以很高的頻率在我們學習工作中重復出現,最近在工作中遇到了跨域的相關問題,這里我把它總結記錄一下。關于跨域,有N種類型,現在我只專注于ajax請求跨域(ajax跨域只是屬于瀏覽器同源策略中的一部分,其它的這里不做介紹),內容...
摘要:關于,強烈推薦閱讀跨域資源共享詳解阮一峰另外,這里也整理了一個實現原理圖簡化版如何判斷是否是簡單請求瀏覽器將請求分成兩類簡單請求和非簡單請求。 前言 從剛接觸前端開發起,跨域這個詞就一直以很高的頻率在身邊重復出現,一直到現在,已經調試過N個跨域相關的問題了,16年時也整理過一篇相關文章,但是感覺還是差了點什么,于是現在重新梳理了一下。 個人見識有限,如有差錯,請多多見諒,歡迎提出iss...
摘要:需注意的是由于同源策略的限制,所讀取的為跨域請求接口所在域的,而非當前頁。目前,所有瀏覽器都支持該功能需要使用對象來支持,也已經成為主流的跨域解決方案。反向代理接口跨域跨域原理同源策略是瀏覽器的安全策略,不是協議的一部分。 什么是跨域? 跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這里跨域是廣義的。 廣義的跨域: 1.) 資源跳轉: A鏈接、重定向、表單提交 2.) 資源...
摘要:上節我們講了同源策略,這節我們講講如何跨域。當這些從的腳本執行出錯,因為違背了同源策略為了保證用戶信息不被泄露,錯誤信息不會顯示出來,取而代之只會返回一個。 前端最基礎的就是 HTML+CSS+Javascript。掌握了這三門技術就算入門,但也僅僅是入門,現在前端開發的定義已經遠遠不止這些。前端小課堂(HTML/CSS/JS),本著提升技術水平,打牢基礎知識的中心思想,我們開課啦(每...
閱讀 3610·2023-04-26 02:24
閱讀 943·2023-04-25 14:47
閱讀 2515·2021-11-24 11:16
閱讀 1733·2021-11-24 09:38
閱讀 1583·2021-11-18 10:07
閱讀 2073·2021-09-22 15:49
閱讀 1602·2019-08-30 15:55
閱讀 892·2019-08-26 13:38