前端人員都懂的瀏覽器的同源策略,以及如何進行不同源間的相互訪問
引言
作為前端開發人員,你要是連同源策略都不知道是什麼,那就太說不過去了。本篇文章將講述同源策略的定義, 以及當我們需要克服同源策略,如何進行跨域訪問資料的方法。
正文
一、同源策略的定義
「同源策略」
: 瀏覽器自帶的一種安全策略,他是指
協議
、
域名
、
埠
三個都相同的才能互相訪問,即若協議、域名、埠有一個不相同時,瀏覽器禁止頁面載入或執行與自身不同域的指令碼。
那既然有同源的概念,那必定有不同源的概念,接下來我們來看一個組例子, 理解一下什麼是同源,什麼是不同源。
url
是否同源(以及原因)
http://www。
example。com:80
該 url 與下列的 url 比較
http://www。
example。com:80/index。ht
ml
同源(協議、域名、埠都相同)
http://www。
example。com:5000
不同源(埠不同)
https://www。
example。com:80
不同源(協議不同)
http://www。
each。com:80
不同源(域名不同)
為什麼瀏覽器會有同源策略? 因為如果沒有同源策略,別人就可以輕鬆的獲取我們網站的 cookie 資訊, 或是對網頁進行DOM操作, 要知道這都是非常恐怖的, 尤其是 cookie 資訊, 它裡面存在著 sessionID ,這是與服務端的 session 會話的重要憑證, 要是被別人得到了 cookie , 可能會造成資料被盜取等後果。
二、同源策略的應用
上面瞭解了同源策略的定義,但是那還是挺抽象的,那我們接下來來看一下實戰中的同源策略是什麼樣的,藉此來更深刻的理解一下同源策略的定義。
我們的主體網址是:
http://localhost:5000/
「請求與自身同域的指令碼檔案」
我們透過jquery的 ajax 來請求 http://localhost:5000/ 下的 data。js 指令碼檔案
<!
DOCTYPE
html
>
<
html
lang
=
“en”
>
<
head
>
<
meta
charset
=
“UTF-8”
>
<
title
>
Title
<
/title>
<
/head>
<
body
>
<
script
src
=
“https://code。jquery。com/jquery-3。5。1。min。js”
><
/script>
<
script
>
$
。
ajax
({
url
:
‘http://localhost:5000/data。js’
,
type
:
‘get’
})
。
done
(
data
=>
{
console
。
log
(
data
)
})
<
/script>
<
/body>
<
/html>
因為
http://localhost:5000/data。js
與
http://localhost:5000/
是同源的,所以成功請求到了 data。js 指令碼檔案中的資料, 瀏覽器也沒有報錯。
「請求與自身不同域的指令碼檔案」
我們透過jquery的 ajax 來請求
http://www。
example。com:5000/
下的 data。js 指令碼檔案
<!
DOCTYPE
html
>
<
html
lang
=
“en”
>
<
head
>
<
meta
charset
=
“UTF-8”
>
<
title
>
Title
<
/title>
<
/head>
<
body
>
<
script
src
=
“https://code。jquery。com/jquery-3。5。1。min。js”
><
/script>
<
script
>
$
。
ajax
({
url
:
‘http://www。example。com:5000/data。js’
,
type
:
‘get’
})
。
done
(
data
=>
{
console
。
log
(
data
)
})
<
/script>
<
/body>
<
/html>
因為
http://www。example:5000/data。js
與
http://localhost:5000/
是不同源的,所以瀏覽器會報出以下錯誤:
這個錯誤大致的意思就是說因為瀏覽器的同源策略,無法透過該域的網址去訪問別的域下的指令碼檔案, 這就是瀏覽器同源策略起到的作用。
想必大家已經對同源策略有了一定的瞭解了。那麼如果我們有時真的要去訪問別的域下的指令碼檔案,但因為瀏覽器存在同源策略,那我們該怎麼辦呢?繼續往下看, 看看如何解決這一問題。
三、實現不同域的指令碼檔案訪問
實現不同域的指令碼檔案訪問的方法有很多種,以下舉幾個例子:
透過html幾個特殊的標籤進行訪問
透過jsonp來實現跨域請求
透過CORS(跨域資源共享)實現跨域請求
透過代理實現跨域請求(例如nginx 、node中介軟體)
(1)透過html幾個特殊的標籤進行訪問
其實在 html 裡有幾個標籤是存在
src
屬性的,例如
、
、
img
、
。 這些標籤的
src
屬性是不會受到瀏覽器的同源策略的限制,是可以對不同域下的指令碼檔案進行訪問的。舉個例子:
<!
DOCTYPE
html
>
<
html
lang
=
“en”
>
<
head
>
<
meta
charset
=
“UTF-8”
>
<
title
>
Title
<
/title>
<
/head>
<
body
>
<
script
src
=
“https://code。jquery。com/jquery-3。5。1。min。js”
><
/script>
<
/body>
<
/html>
我們應該都知道 jquery 可以用外部連結引入吧,這就是透過
src
屬性,避開了同源策略的限制的一個典型例子。
(2)透過jsonp來實現跨域請求
看到 jsonp 就能猜到,這個方法是在需要跨域請求資料時用到的,接下來我們直接來看如何使用。
原生實現jsonp跨域請求
<!
DOCTYPE
html
>
<
html
lang
=
“en”
>
<
head
>
<
meta
charset
=
“UTF-8”
>
<
title
>
Title
<
/title>
<
/head>
<
body
>
//在script標籤的src屬性後面,拼接上一個 callback=回撥函式名
<
script
src
=
“http://www。example。com:5000/data。js?callback=showDate”
><
/script>
<
script
>
//會在跨域請求後,呼叫該函式
function
showDate
(
data
)
{
console
。
log
(
data
)
}
<
/script>
<
/body>
<
/html>
jquery 實現 jsonp跨域請求
實際上jquery 將jsonp封裝在 ajax請求中,原理的話其實就是建立了一個script標籤,然後拼接 url 字串,作為 src 屬性的值。
<!
DOCTYPE
html
>
<
html
lang
=
“en”
>
<
head
>
<
meta
charset
=
“UTF-8”
>
<
title
>
Title
<
/title>
<
/head>
<
body
>
<
script
src
=
“node_modules/jquery/dist/jquery。min。js”
><
/script>
<
script
>
$
(
function
()
{
function
showDate
(
data
)
{
console
。
log
(
data
)
}
$
。
ajax
({
url
:
‘http://www。example。com:5000/data。js’
,
type
:
‘get’
,
//請求方式必須為 get
dataType
:
‘jsonp’
,
//資料型別改為 jsonp
jsonpCallback
:
‘showDate’
//資料返回後呼叫的回撥函式
})
。
done
(
data
=>
{
console
。
log
(
data
)
})
})
<
/script>
<
/body>
<
/html>
這樣就實現了跟原生一樣的透過 jsonp 實現跨域請求的效果。
(3)透過CORS(跨域資源共享)實現跨域請求
CORS 這個縮寫是不是特別看著特別眼熟?沒錯,在上面我們做了一個跨域請求報錯的例項,圖中的報錯資訊就有這個縮寫單詞在內, 所以透過CORS(跨域資源共享)也是可以實現跨域請求。 因為這個我研究的不太深,我就簡單來說一下怎麼用吧。
我們需要向
http://www。
example。com:5000/
請求它下面的 data。js 指令碼檔案, 我們就只需要服務端給相應頭設定一下屬性即可,即可完成無論誰跨域請求該域下的 data。js , 都不會因為同源策略而報錯, 所以其實這個也有點不太好, 誰都可以訪問,那豈不是很危險。
Access
-
Control
-
Allow
-
Origin
:*
Access
-
Control
-
Allow
-
Methods
:
POST
,
GET
,
OPTIONS
Access
-
Control
-
Allow
-
Headers
:
Origin
,
x
-
requested
-
with
,
content
-
type
,
Accept
這個方法我描述的比較模糊, 因為我也沒有深入研究過,所以可能會有點錯誤,但這確實是一種跨域請求的方法,如果有感興趣的小夥伴可以去看一下阮一峰老師的一個講解CORS的日誌——跨域資源共享 CORS 詳解 - 阮一峰的網路日誌
(4)透過代理實現跨域請求
我們都知道同源策略是瀏覽器自帶的,那麼我們如果要避免同源策略進行跨域請求,我們可以透過代理伺服器的方式進行請求,例如我們請求一個與自身不同域的指令碼檔案,那麼我們可以先請求與自身同域的一個 url ,然後透過代理伺服器進行跳轉, 最後返回由代理伺服器請求到的指令碼檔案,這樣說比較抽象,我們用一個node的中介軟體來舉例說一下(其實nginx也可以):
//引入 express 框架
const
express
=
require
(
‘express’
);
//引入 代理中介軟體
const
{
createProxyMiddleware
}
=
require
(
‘http-proxy-middleware’
);
//建立服務例項
const
app
=
express
();
// 使用一下代理中介軟體,第一個引數為我們需要代理的 url
// 第二個引數為跳轉的 url
app
。
use
(
‘/api’
,
createProxyMiddleware
({
target
:
‘http://www。example。com:5000’
,
changeOrigin
:
true
}));
//監聽5000埠
app
。
listen
(
5000
);
按照以上配置完以後, 我們請求
http://localhost:5000/api/data。js
時, 代理伺服器就會自動跳轉到
http://www。example。com:5000/data。js
, 這樣的話我們就完成跨域請求, 並且瀏覽器也不會報錯。
如果想具體學習一下的小夥伴可以去 github 上看一下這個中介軟體作者的詳細介紹,下面附上跳轉的連結——http-proxy-middleware的GitHub地址
其實 nginx也可以完成代理的作用,這裡就不多做解釋了,如果想要了解的可以去查詢一下文件,自行學習一下。
結束語
好了,關於同源策略也介紹的差不多了, 有些寫的詳細,有些寫的簡略,那也是作者的水平的體現了, 等我以後水平高了,會繼續完善該文章的。希望本篇文章對大家能有所幫助, 若有哪裡寫的不對, 也歡迎大家評論指正,謝謝~
公眾號:
前端印象,
歡迎關注,一起前端交流