您好,登錄后才能下訂單哦!
這篇文章主要講解了“CORS怎么設置多域名”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“CORS怎么設置多域名”吧!
CORS 即跨域資源共享 (Cross-Origin Resource Sharing, CORS)。簡而言之,就是在服務器端的響應中加入幾個標頭,使得瀏覽器能夠跨域訪問資源。
這個響應頭的字段設置就是 Access-Control-Allow-Origin: *
以下是最簡單的一個 CORS 請求
GET / HTTP/1.1
Host: shanyue.tech
Origin: http://shanyue.tech
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: text/plain; charset=utf-8
Content-Length: 12
Date: Wed, 08 Jul 2020 17:03:44 GMT
Connection: keep-alive
當一個請求跨域且不是簡單請求時就會發起預請求,也就是 Options
。如果沒有預請求,萬一有一個毀滅性的 POST 跨域請求直接執行,雖然最后告知瀏覽器你沒有跨域權限,但是損失已造成,豈不虧大的。
以下條件構成了簡單請求:
Method
: 請求的方法是
GET
、
POST
及
HEAD
Header
: 請求頭是
Content-Type
(有限制)、
Accept-Language
、
Content-Language
等Content-Type
: 請求類型是
application/x-www-form-urlencoded
、
multipart/form-data
或
text/plain
非簡單請求一般需要開發者主動構造,在項目中常見的 Content-Type: application/json
及 Authorization: <token>
為典型的「非簡單請求」。與之有關的三個字段如下:
Access-Control-Allow-Methods
: 請求所允許的方法,
「用于預請求 (preflight request) 中」Access-Control-Allow-Headers
: 請求所允許的頭,
「用于預請求 (preflight request) 中」Access-Control-Max-Age
: 預請求的緩存時間既然 CORS 原理如此簡單,那就拿起鍵盤寫一個簡單的 CORS 中間件吧,CORS 大致是設置幾個響應頭吧
「關于 CORS 的設置即是對 CORS 相關響應頭的設置,因此了解這些 headers 至關重要。無論對于配置的生產者和消費者,及后端和前端而言,都應該掌握!」
以下是關于 CORS 相關的 response headers 及其釋義
Access-Control-Allow-Origin
: 可以把資源共享給那些域名,支持 * 及 特定域名Access-Control-Allow-Credentials
: 請求是否可以帶 cookieAccess-Control-Allow-Methods
: 請求所允許的方法,
「用于預請求 (preflight request) 中」Access-Control-Allow-Headers
: 請求所允許的頭,
「用于預請求 (preflight request) 中」Access-Control-Expose-Headers
: 那些頭可以在響應中列出Access-Control-Max-Age
: 預請求的緩存時間而關于 CORS 的中間件即是使用默認值與配置來設置這些頭,如 koa/cors
需要傳遞以下參數。
/**
* CORS middleware
*
* @param {Object} [options]
* - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header
* - {String|Array} allowMethods `Access-Control-Allow-Methods`, default is 'GET,HEAD,PUT,POST,DELETE,PATCH'
* - {String|Array} exposeHeaders `Access-Control-Expose-Headers`
* - {String|Array} allowHeaders `Access-Control-Allow-Headers`
* - {String|Number} maxAge `Access-Control-Max-Age` in seconds
* - {Boolean|Function(ctx)} credentials `Access-Control-Allow-Credentials`, default is false.
* - {Boolean} keepHeadersOnError Add set headers to `err.header` if an error is thrown
* @return {Function} cors middleware
* @api public
*/
// Example
app.use(cors())
由上,貌似很簡單,只需要服務端設置一下 Access-Control-Allow-Origin
就可以輕松解決問題,但其中的坑有可能比你想象地要多很多!
先說回 Access-Control-Allow-Origin
,它所允許的值只有兩個
*
: 所有域名shanyue.tech
: 特定域名此時,新問題來了:
?CORS 如果需要指定多個域名怎么辦[3]
?
「如果使用 Access-Control-Allow-Origin: *
,則所有的請求不能夠攜帶 cookie
」,因此這種方案被擯棄。
因此這個問題需要寫代碼來解決,根據請求頭中的 Origin 來設置響應頭 Access-Control-Allow-Origin
Access-Control-Allow-Origin: <Origin>
// 獲取 Origin 請求頭
const requestOrigin = ctx.get('Origin');
// 如果沒有,則跳過
if (!requestOrigin) {
return await next();
}
// 設置響應頭
ctx.set('Access-Control-Allow-Origin', requestOrigin)
「但此時會出現一個新的問題:緩存」
在討論與 Vary
關系時,先拋出一個問題:
?如何避免 CDN 為 PC 端緩存移動端頁面[4]
?
假設有兩個域名訪問 static.shanyue.tech
的跨域資源
foo.shanyue.tech
,響應頭中返回
Access-Control-Allow-Origin: foo.shanyue.tech
bar.shanyue.tech
,響應頭中返回
Access-Control-Allow-Origin: bar.shanyue.tech
看起來一切正常,但平靜的水面下波濤暗涌:
「如果 static.shanyue.tech
資源被 CDN 緩存,bar.shanyue.tech
再次訪問資源時,因緩存問題,因此此時返回的是 Access-Control-Allow-Origin: foo.shanyue.tech
,此時會有跨域問題」
此時,Vary: Origin
就上場了,代表為不同的 Origin
緩存不同的資源,這在各個服務器端 CORS 中間件也能體現出來,如以下幾段代碼
此處是一段 koa 關于 CORS 的處理函數: 詳見 koajs/cors[5]
return async function cors(ctx, next) {
// If the Origin header is not present terminate this set of steps.
// The request is outside the scope of this specification.
const requestOrigin = ctx.get('Origin');
// Always set Vary header
// https://github.com/rs/cors/issues/10
ctx.vary('Origin');
}
此處是一段 Go 語言關于 CORS 的處理函數: 詳見 rs/cors[6]
func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
headers := w.Header()
origin := r.Header.Get("Origin")
// Always set Vary, see https://github.com/rs/cors/issues/10
headers.Add("Vary", "Origin")
}
進一步改進相關代碼:
// 獲取 Origin 請求頭
const requestOrigin = ctx.get('Origin');
// 不管有沒有跨域都要設置 Vary: Origin
ctx.set('Vary', 'Origin')
// 如果沒有設置,說明沒有跨域,跳過
if (!requestOrigin) {
return await next();
}
// 設置響應頭
ctx.set('Access-Control-Allow-Origin', requestOrigin)
「那此時是不關于 CORS
的問題就解決了?從中間件處理層面是這樣的,但仍然有一些服務端中間件使用問題及瀏覽器問題」
HSTS (HTTP Strict Transport Security) 為了避免 HTTP 跳轉到 HTTPS 時遭受潛在的中間人攻擊,由瀏覽器本身控制到 HTTPS 的跳轉。如同 CORS 一樣,它也是有一個服務器的響應頭來控制
Strict-Transport-Security: max-age=5184000
此時瀏覽器訪問該域名時,會使用 307 Internal Redirect
,無需服務器干涉,自動跳轉到 HTTPS 請求。
「如果前端訪問 HTTP 跨域請求,此時瀏覽器通過 HSTS 跳轉到 HTTPS,但瀏覽器不會給出相應的 CORS 響應頭部,就會發生跨域問題。」
GET / HTTP/1.1
Host: shanyue.tech
Origin: http://shanyue.tech
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
當與其他中間件一起工作時,也有可能出現問題,由于不正確的執行順序也可能導致跨域失敗。
假設有一個參數校驗中間件,置于 CORS 中間件上方,由于校驗失敗,并未穿過 CORS 中間件,在前端會報錯跨域失敗,真正的參數校驗問題掩蓋其中。
const Koa = require('koa')
const app = new Koa()
const cors = require('@koa/cors')
// 異常處理中間件
app.use(async (ctx, next) => {
try {
await next()
} catch (e) {
ctx.body = 'hello, error'
}
})
// 某一個特定時刻肯定會報錯的中間件
app.use(async (ctx, next) => {
throw new Error('hello, world')
})
// CORS 中間件
app.use(cors())
app.listen(3000)
感謝各位的閱讀,以上就是“CORS怎么設置多域名”的內容了,經過本文的學習后,相信大家對CORS怎么設置多域名這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。