人不可能踏進同一條河流,我可以一天在同一個問題上摔倒兩次。
這次是跨域問題,都是淚,教程提供的服務端代碼雖然配置了文件,但是依然是沒有解決跨域問題,依然報錯 Request header field content-type is not allowed by Aceess-Control-Allow-Header in preflight response.
整個跨域代碼全部注釋掉換上
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header("X-Powered-By",' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
問題解決。
————————————————————————————
2020.12.22補一次更新,這個問題隨着工作時間的增長,現在過去幾個月了,對跨域的理解也更加深入。
一.問題產生的原因
1.什么是同源?
出於瀏覽器的同源策略限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。同源策略會阻止一個域的javascript腳本和另外一個域的內容進行交互。所謂同源(即指在同一個域)就是兩個頁面具有相同的協議(protocol),主機(host)和端口號(port)。
比如你的網站的頁面地址在:http://127.0.0.1:8080,然后你向后台發送了一次POST請求,但是后台的地址為:http://10.0.0.1:5050,此時的IP地址並不一樣(主域名/IP不同)就非常明顯的違背了同源政策,即為跨域,那么作為一個前端人員,跨域並不是前端的原因,而是后台的原因(甩鍋),就好比后台做了一個接口,但是接口並不允許跨域的請求訪問這個接口,如果是前后端分離式開發,此問題可直接讓后台添加跨域請求允許就好了。
那么問題來了,后台是自己(比如自己搭的NODE后台,或者請求本地資源,也報了這個跨域的錯誤),此時怎么解決呢?剛好我也遇到了這個問題,其實很簡單,仔細理解一下跨域就知道問題在哪里了,接下來繼續往下面看。
首先,同源限制了哪些條件?
| 當前頁面url | 被請求頁面url | 是否跨域 | 原因 |
| http://www.test.com/ | http://www.test.com/index.html | 否 | 同源(協議、域名、端口號相同) |
| http://www.test.com/ | https://www.test.com/index.html | 跨域 | 協議不同(http/https) |
| http://www.test.com/ | http://www.baidu.com/ | 跨域 | 主域名不同(test/baidu) |
| http://www.test.com/ | http://blog.test.com/ | 跨域 | 子域名不同(www/blog) |
| http://www.test.com:8080/ | http://www.test.com:7001/ | 跨域 | 端口號不同(8080/7001) |
下面來談談解決方案
第一,在我們搭建NODE的后台框架的時候,如果沒有配置跨域允許,是會阻擋跨域請求的。
解決辦法為,增加一個中間件處理(此處默認使用了EXpress或Koa框架的后台),在后台代碼中,加入我之前寫的那段代碼就好了
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header("X-Powered-By",' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
這段代碼,大概就是增加了允許訪問后台的一些請求頭(header)、方法(PUT,POST,GET,DELETE,OPTIONS)等
第一句則是意思為允許所有origin源訪問(此處還有一坑,我后面再描述)
如果后台這樣配置了卻依然沒有解決的話,就仔細檢查一下前后端是否在Origin、Headers、Methods、Content-Type的配置上是不是有不一樣的地方,以ajax請求為例,例如他錯誤提示為文件類型不允許,那么就需要前端在請求中加入"Content-Type"這一項配置,與后台配置相吻合,其他的也是一樣。
以上,自己搭建的NODE跨域問題就基本解決了,此外node里有一個第三方模塊:cors,可以直接npm install 一下,然后引入、使用,只用兩句代碼就可以簡單實現跨域允許,就省去上面一大段代碼了。
第二,我自己根本就沒有搭什么后台,我也沒有訪問后台呀,我就是請求我自己本地的資源也報這個錯誤了!是為什么呢?
這個坑我遇到了,原因也是在對同源政策的理解上,眾所周知,我們本地的地址有好多種表達方式,localhost,127.0.0.0,以及自己在局域網中的IP地址,這就有3個了,如果加上公網IP那就是四個了,但是這四個地址之間也是會發生跨域的!例如我在代碼中寫的請求地址為:localhost/,但是我在局域網中運行了,瀏覽器的IP地址為10.0.0.1/index.html,此時localhost和10.0.0.1也是會發生跨域的,不信你把10.0.0.1換成localhost試試。
————————————————————————————
2021-8-14 補更新
前兩天使用axios進行請求時,又遇到了跨域的問題,跨域的問題又出現了,究其原因是在axios中就會對get請求的整個url進行encodeURI,導致有些get方法不能傳[]
場景:
其他請求接口都正常,GET請求參數中,傳參了一個空的數組,導致跨域,仔細對比,空數組在經過axios未經過編碼。
解決方法:
在axios中間件處理中加入以下代碼:
myAxios.interceptors.request.use( config => { let url = config.url // get參數編碼 if (config.method === 'get' && config.params) { url += '?' let keys = Object.keys(config.params) for (let key of keys) { url += `${key}=${encodeURIComponent(config.params[key])}&` } url = url.substring(0, url.length - 1) config.params = {} } config.url = url return config },
