解決跨域問題(CORS樱溉、JSONP)

1 同源策略

1.1 同源

  • window.origin或者location.origin可以得到當(dāng)前源
  • 源 = 協(xié)議 + 域名 + 端口號(hào)
  • 如果有兩個(gè)url的 協(xié)議构订、域名丛塌、端口號(hào)完全一致空凸,那么這兩個(gè)url就是同源的
  • 在瀏覽器里打開頁(yè)面則默認(rèn)遵循同源策略
  • 前端測(cè)試時(shí)可以使用 postman 等工具嚎花,或安裝在chrome里安裝插件進(jìn)行測(cè)試(不遵循同源策略,僅測(cè)試開發(fā)時(shí)可以使用)呀洲。

1.2 同源策略定義

  • 如果JS運(yùn)行在源A里紊选,那么就只能獲取源A的數(shù)據(jù)
  • 不能獲取源B的數(shù)據(jù),即不允許跨域
  • 不同源的頁(yè)面之間道逗,不準(zhǔn)互相訪問數(shù)據(jù)

1.3 優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

保證用戶的隱私安全和數(shù)據(jù)安全

缺點(diǎn)

當(dāng)前端需要訪問另一個(gè)域名的后端接口時(shí)兵罢,會(huì)被瀏覽器阻止其獲取相應(yīng)。
eg:A 站點(diǎn)通過(guò) AJAX 訪問 B 站點(diǎn)的 /money 查詢余額接口滓窍,請(qǐng)求可以發(fā)出卖词,但響應(yīng)會(huì)被瀏覽器屏蔽

1.4 疑問解答

  • a.qq.com和qq.com跨域:歷史上出現(xiàn)過(guò)不同公司共用域名,因此這兩者不一定是同一個(gè)網(wǎng)站吏夯,瀏覽器謹(jǐn)慎起見此蜈,認(rèn)為這是不同的源
  • 不同端口算跨域:一個(gè)端口一個(gè)公司,因此不同端口可能屬于不同公司噪生,因此認(rèn)為是不同的源
  • 同IP跨域:原因同上裆赵,IP是可以共用的
  • 跨域可以使用CSS、JS和圖片等:同源策略限制的是數(shù)據(jù)訪問跺嗽,我們引用CSS战授、JS和圖片時(shí),其實(shí)并不知道其內(nèi)容桨嫁,只是在引用

1.5 跨域的解決方法

跨域問題根源:

  • 瀏覽器默認(rèn)不同源之間不能互相訪問數(shù)據(jù)

解決方法:

  • 方法1:CORS(不支持IE)
  • 方法2:JSONP(script標(biāo)簽存在缺陷)

2 CORS

  • 在server.js中進(jìn)行設(shè)置陈醒,在需要跨域訪問的文件設(shè)置中添加以下代碼:
// 'http://xxxx:yyyy為設(shè)置允許訪問這部分資源的網(wǎng)站地址及端口號(hào)
response.setHeader('Access-Control-Allow-Origin','http://xxxx:yyyy')
  • referer
    可以通過(guò)console.log(request.headers['referer'])讀取想要獲取此資源的網(wǎng)站

存在問題
無(wú)法兼容IE6、7瞧甩、8、9瀏覽器弥鹦,因此如果需要兼容IE瀏覽器肚逸,則需要使用JSONP

3 JSONP

3.1 簡(jiǎn)介

3.1.1 概念

在進(jìn)行跨域操作時(shí),由于部分瀏覽器不支持CORS彬坏,因此我們必須使用JSONP來(lái)執(zhí)行跨域操作朦促,我們需要請(qǐng)求一個(gè)JS文件,JS文件中會(huì)執(zhí)行一個(gè)回調(diào)栓始,回調(diào)中包含我們所需的數(shù)务冕,回調(diào)的名稱是隨機(jī)生成的隨機(jī)數(shù),我們將這個(gè)隨機(jī)數(shù)名稱以callback的參數(shù)傳給后臺(tái)幻赚,后臺(tái)會(huì)將函數(shù)返回給我們并執(zhí)行禀忆。

3.1.2 優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 兼容IE
  • 可以跨域

缺點(diǎn)

  • 由于它是script標(biāo)簽臊旭,所以它無(wú)法讀取到AJAX那么精確,接收不到狀態(tài)碼及響應(yīng)頭等
  • 由于它是script標(biāo)簽箩退,因此它只能發(fā)get請(qǐng)求离熏,不支持post

3.2 原理

通過(guò)依靠域內(nèi)js獲取域內(nèi)json的內(nèi)容,而后使用域外js調(diào)用域內(nèi)獲取到內(nèi)容的js戴涝,從而獲得域內(nèi)json的內(nèi)容

3.3 使用方法(以獲取json文件內(nèi)容為例)

  • 在json所在域內(nèi)設(shè)置同域js文件用于獲取json文件內(nèi)容
  • js文件內(nèi)使用占位符預(yù)留json內(nèi)容放置空間
  • 在域內(nèi)server.js文件中設(shè)置滋戳,使用域內(nèi)js文件獲取域內(nèi)對(duì)應(yīng)json文件內(nèi)容
  • 域外則可以通過(guò)引用域內(nèi)js文件,獲取域內(nèi)json文件內(nèi)容

3.4 實(shí)例

要求:
1.sherry.com需要獲取qq.com域內(nèi)friend.json的數(shù)據(jù)
2.為回調(diào)函數(shù)設(shè)置隨機(jī)函數(shù)名啥刻,以避免函數(shù)名被占用
3.通過(guò)referer設(shè)置僅限http://sherry.com:9999可以訪問friend.json的內(nèi)容

// qq.com內(nèi)friend.json的內(nèi)容
{
  "name": "sherry",
  "age": 18
}


// 在sherry.js定義隨機(jī)函數(shù)奸鸯,并打印數(shù)據(jù),sherry.com可以通過(guò)window[random]獲取數(shù)據(jù)
// window[random]是回調(diào)函數(shù)
const random =  Math.random()
window[random] = (data) => {
    console.log(data)
}


// qq.com內(nèi)server.js設(shè)置
else if (path === '/friend.js') {
        // referer判定是否為http://sherry.com:9999可帽,是進(jìn)行操作娄涩,不是則返回404
        if (request.headers['referer'].indexOf('http://sherry.com:9999') === 0) {
            response.statusCode = 200
            response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
            const string = `window[{{xxx}}] = {{data}}`
            const data = fs.readFileSync('./public/friend.json').toString()
            // 使用獲取到的隨機(jī)函數(shù)名query.functionName替換friend.js內(nèi)的函數(shù)名占位符{{xxx}}
            string2 = string.replace('{{data}}', data).replace('{{xxx}}', query.callback)
            response.write(string2)
            response.end()
        } else {
            response.statusCode = 404
            response.end()
        }
    }


// sherry.com用于引用friend.js以獲取friend.json內(nèi)容的sherry.js設(shè)置
// 方法1:JS動(dòng)態(tài)引用
const  script = document.createElement('script')
// 通過(guò)functionName=${random}傳入隨機(jī)函數(shù)名
const script = document.createElement('script')
script.src = `http://qq.com:8888/friend.js?functionName=${random}`
// 執(zhí)行完畢后刪除多余的script,保證頁(yè)面整潔
script.onload = () => {
    script.remove()
}
document.body.appendChild(script)

// 方法2:HTML靜態(tài)引用
// 在sherry.js對(duì)應(yīng)的index.html頁(yè)面設(shè)置
<script src="http://qq.com:8888/friend.js"></script>
// 在sherry.js中設(shè)置蘑拯,用以監(jiān)聽內(nèi)容是否獲取成功
console.log(window.xxx)



代碼封裝jsonp()

function jsonp(url) {
    return new Promise((resolve, reject) => {
        const random = Math.random()
        window[random] = data => {
            resolve(data);
        };
        const script = document.createElement("script")
        script.src = `${url}?callback=${random}`
        script.onload = () => {
            script.remove();
        };
        script.onerror = () => {
            reject();
        };
        document.body.appendChild(script);
    });
}

// jsonp的使用
jsonp('http://qq.com:8888/friend.js')
    .then((data) => {
        console.log(data)
    })

3.4 缺陷及解決

任意網(wǎng)站都可以通過(guò)引用JS獲取域內(nèi)數(shù)據(jù)钝满,可以通過(guò)referer檢查來(lái)避免這個(gè)缺陷

// 檢查是否是允許的網(wǎng)站,是則放行申窘,不是則返回404
if (request.headers['referer'].indexOf('http://sherry.com:9999') === 0) {
            response.statusCode = 200
            response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
            const string = fs.readFileSync('./public/friend.js').toString()
            const data = fs.readFileSync('./public/friend.json').toString()
            string2 = string.replace('{{data}}', data)
            response.write(string2)
            response.end()
        } else {
            response.statusCode = 404
            response.end()
        }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弯蚜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子剃法,更是在濱河造成了極大的恐慌碎捺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贷洲,死亡現(xiàn)場(chǎng)離奇詭異收厨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)优构,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門诵叁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人钦椭,你說(shuō)我怎么就攤上這事拧额。” “怎么了彪腔?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵侥锦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我德挣,道長(zhǎng)恭垦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮番挺,結(jié)果婚禮上唠帝,老公的妹妹穿的比我還像新娘。我一直安慰自己建芙,他們只是感情好没隘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著禁荸,像睡著了一般右蒲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赶熟,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天瑰妄,我揣著相機(jī)與錄音,去河邊找鬼映砖。 笑死间坐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的邑退。 我是一名探鬼主播竹宋,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼地技!你這毒婦竟也來(lái)了蜈七?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤莫矗,失蹤者是張志新(化名)和其女友劉穎飒硅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體作谚,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡三娩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妹懒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雀监。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖眨唬,靈堂內(nèi)的尸體忽然破棺而出滔悉,到底是詐尸還是另有隱情,我是刑警寧澤单绑,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站曹宴,受9級(jí)特大地震影響搂橙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一区转、第九天 我趴在偏房一處隱蔽的房頂上張望苔巨。 院中可真熱鬧,春花似錦废离、人聲如沸侄泽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悼尾。三九已至,卻和暖如春肖方,著一層夾襖步出監(jiān)牢的瞬間闺魏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工俯画, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留析桥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓艰垂,卻偏偏與公主長(zhǎng)得像泡仗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子猜憎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容