跨域如何解決

同源策略SOP(Same origin policy)是一種約定(即"協(xié)議+域名+端口"三者相同)概龄,它是瀏覽器最核心也最基本的安全功能右蹦,如果缺少了同源策略厕诡,瀏覽器很容易受到攻擊烟很。協(xié)議谴垫,域名竖伯,端口一種不同都是不同源,即跨域了
跨域會(huì)有如下限制:
1.Cookie存哲、LocalStorage 和 IndexDB 無(wú)法讀取
2.DOM 和 Js對(duì)象無(wú)法獲得

  1. AJAX 請(qǐng)求不能發(fā)送
  • 解決跨域的方法:

一、通過(guò)jsonp跨域

1.原生實(shí)現(xiàn)
js七婴、css虏缸,img等靜態(tài)資源不受跨域的限制遍膜,可以通過(guò)動(dòng)態(tài)創(chuàng)建script,來(lái)解決跨域問(wèn)題.

下面這個(gè)html頁(yè)面和需要訪問(wèn)的php文件在同一協(xié)議,同一域名钠怯,不同端口下虱岂,所以是跨域請(qǐng)求

  • index.html
<body>
<a>某個(gè)頁(yè)面</a><input type="button" value="想通過(guò)ajax去請(qǐng)求數(shù)據(jù)">
<script>

   function getInfo(obj){
       //得到數(shù)據(jù) 解析到頁(yè)面
       console.log(obj);
       //解析數(shù)據(jù)
   }

    document.querySelector("input").onclick = function(){
        //XMLHttpRequest 去請(qǐng)求會(huì)有跨域限制,所以下面注釋的這種方法不能使用
        // var xhr = new XMLHttpRequest();
        // xhr.open("get","http://localhost/getData.php");
        // xhr.send(null);
        // xhr.onreadystatechange = function(){
        //     if(xhr.readyState === 4 && xhr.status === 200){
        //         var data = xhr.responseText;
        //         console.log(data);
        //     }
        // }

        var script = document.createElement("script");

        script.src = "http://localhost/getData.php?callback=getInfo";//傳參一個(gè)回調(diào)函數(shù)名給后端屯伞,攜帶后端數(shù)據(jù)再執(zhí)行前端的這個(gè)回調(diào)函數(shù)
     
        document.body.appendChild(script);  //讓這個(gè)標(biāo)簽去發(fā)送請(qǐng)求 必須把這個(gè)標(biāo)簽掛載到頁(yè)面上
    }
</script>
</body>
  • getData.php
 <?php

    $Info = $_GET['callback']; //getInfo函數(shù)
    //向客戶端輸出 getInfo("GetData");
    //組拼一個(gè)getInfo("GetData")
    echo $Info."("."'GetData'".")";
?>
index.html

后端獲取到的數(shù)據(jù)

點(diǎn)擊按鈕獲取到后端數(shù)據(jù)违帆,執(zhí)行函數(shù)的結(jié)果

2. jquery ajax

$.ajax({
    url: 'http://localhost/getData.php',
    type: 'get',
    dataType: 'jsonp',  // 請(qǐng)求方式為jsonp
    jsonpCallback: "getInfo",    // 自定義回調(diào)函數(shù)名
    data: {}
});
jsonp缺點(diǎn):

1、只能實(shí)現(xiàn)get一種請(qǐng)求:
??因?yàn)閐ocument.createElement('script') 生成一個(gè) script 標(biāo)簽莽鸭,然后插 body 里吗伤。在這里根本沒(méi)有設(shè)置請(qǐng)求格式的余地。(script標(biāo)簽只能進(jìn)行g(shù)et請(qǐng)求)
2硫眨、只支持跨域 HTTP 請(qǐng)求這種情況足淆,不能解決不同域的兩個(gè)頁(yè)面之間如何進(jìn)行 JavaScript 調(diào)用的問(wèn)題
3、調(diào)用失敗的時(shí)候不會(huì)返回各種 HTTP 狀態(tài)碼。
4巧号、安全性族奢,萬(wàn)一假如提供 JSONP 的服務(wù)存在頁(yè)面注入漏洞,即它返回的 javascript 的內(nèi)容被人控制的

二丹鸿、 跨域資源共享(CORS)

普通跨域請(qǐng)求:服務(wù)端只需要設(shè)置Access-Control-Allow-Origin即可越走,前端無(wú)須設(shè)置,若要帶cookie請(qǐng)求:前后端都需要設(shè)置后端需要設(shè)置 Access-Control-Allow-Credentials為true靠欢,前端需要設(shè)置withCredentials為true廊敌。

需注意的是:由于同源策略的限制,所讀取的cookie為跨域請(qǐng)求接口所在域的cookie掺涛,而非當(dāng)前頁(yè)。

在 cors 中會(huì)有簡(jiǎn)單請(qǐng)求復(fù)雜請(qǐng)求的概念

  • 簡(jiǎn)單請(qǐng)求:不會(huì)出發(fā)cors預(yù)檢請(qǐng)求
    1.請(qǐng)求方法是以下三種方法之一:HEAD疼进、GET薪缆、POST
    2.HTTP 的頭信息不超出以下幾種字段:
    ?Accept
    ?Accept-Language
    ?Content-Language
    ?Last-Event-ID
    ?Content-Type(只限于三個(gè)值)
    ??application/x-www-form-urlencoded
    ??multipart/form-data
    ??text/plain
    凡是不同時(shí)滿足上面兩個(gè)條件,就屬于非簡(jiǎn)單請(qǐng)求伞广。
cors的工作原理:

1拣帽、瀏覽器先判斷是簡(jiǎn)單請(qǐng)求還是復(fù)雜請(qǐng)求。
2嚼锄、如果是復(fù)雜請(qǐng)求减拭,在正式請(qǐng)求前瀏覽器會(huì)用OPTIONS方法先發(fā)送一個(gè)預(yù)檢請(qǐng)求OPTIONSHTTP/1.1協(xié)議中定義的方法区丑。

  • 該方法不會(huì)對(duì)服務(wù)器資源產(chǎn)生影響拧粪,預(yù)檢請(qǐng)求中同時(shí)攜帶下面的首部字段:
    Access-Control-Request-Method: 這個(gè)字段表明了請(qǐng)求的方法;
    Access-Control-Request-Headers: 這個(gè)字段表明了這個(gè)請(qǐng)求的 Headers沧侥;
    Origin: 這個(gè)字段表明了請(qǐng)求發(fā)出的域可霎。
  • 服務(wù)器接收到請(qǐng)求后允許攜帶的信息類型:
    Access-Control-Allow-Origin: 能夠被允許發(fā)出這個(gè)請(qǐng)求的域名,也可以使用*來(lái)表明允許所有域名宴杀;
    Access-Control-Allow-Methods: 用逗號(hào)分隔的被允許的請(qǐng)求方法的列表癣朗;
    Access-Control-Allow-Headers: 用逗號(hào)分隔的被允許的請(qǐng)求頭部字段的列表;
    Access-Control-Max-Age: 這個(gè)預(yù)檢請(qǐng)求能被緩存的最長(zhǎng)時(shí)間旺罢,在緩存時(shí)間內(nèi)旷余,同一個(gè)請(qǐng)求不會(huì)再次發(fā)出預(yù)檢請(qǐng)求。
    3扁达、如果是簡(jiǎn)單請(qǐng)求正卧,瀏覽器直接發(fā)出cors請(qǐng)求。會(huì)在頭部信息自動(dòng)的添加origin字段跪解,來(lái)說(shuō)明子來(lái)自哪個(gè)源穗酥。服務(wù)器拿到請(qǐng)求之后,在回應(yīng)時(shí)對(duì)應(yīng)地添加Access-Control-Allow-Origin字段,如果 Origin 不在這個(gè)字段的范圍中砾跃,那么瀏覽器就會(huì)將響應(yīng)攔截骏啰。

1.前端設(shè)置
(1)原生ajax

// 前端設(shè)置是否帶cookie
xhr.withCredentials = true; 
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容

// 前端設(shè)置是否帶cookie
xhr.withCredentials = true;

xhr.open('post', 'http://localhost/index.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(null);

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};

(2)jquery ajax

$.ajax({
    ...
   xhr: {
       withCredentials: true    // 前端設(shè)置是否帶cookie
   },
   crossDomain: true,   // 會(huì)讓請(qǐng)求頭中包含跨域的額外信息,但不會(huì)含cookie
    ...
});

2.后臺(tái)設(shè)置
? 若后端設(shè)置成功抽高,前端瀏覽器控制臺(tái)則不會(huì)出現(xiàn)跨域報(bào)錯(cuò)信息判耕,反之,說(shuō)明沒(méi)設(shè)成功翘骂。
(1)php


//在php中設(shè)置客跨域訪問(wèn)
 if (config('app.environment') == 'local') {  // 如果是本地環(huán)境就允許跨域訪問(wèn) 
            header('Access-Control-Allow-Origin: *');  
            //上面第一行說(shuō)到的Access-Control-Allow-Origin有多種設(shè)置方法:
            //(1)設(shè)置*是最簡(jiǎn)單粗暴的壁熄,但是服務(wù)器出于安全考慮,肯定不會(huì)這么干碳竟,而且草丧,如果是*的話,瀏覽器將不會(huì)發(fā)送cookies莹桅,即使你的XHR設(shè)置了withCredentials
            //(2) 指定域昌执,一般的系統(tǒng)中間都有一個(gè)nginx,所以推薦這種,例如:header("Access-Control-Allow-Origin","http://localhost:3000");
            //(3)動(dòng)態(tài)設(shè)置為請(qǐng)求域诈泼,多人協(xié)作時(shí)懂拾,多個(gè)前端對(duì)接一個(gè)后臺(tái),這樣很方便
            //withCredentials:表示XHR是否接收cookies和發(fā)送cookies铐达,也就是說(shuō)如果該值是false岖赋,響應(yīng)頭的Set-Cookie,瀏覽器也不會(huì)理瓮孙,并且即使有目標(biāo)站點(diǎn)的cookies唐断,瀏覽器也不會(huì)發(fā)送。
            
            header('Access-Control-Allow-Credentials: true'); //是否允許后續(xù)請(qǐng)求攜帶認(rèn)證信息(cookies),該值只能是true,否則不返回
            
            //預(yù)檢請(qǐng)求(參考文章:http://www.php.cn/div-tutorial-378889.html) --- 一般不用設(shè)置
            //與簡(jiǎn)單請(qǐng)求不同的是杭抠,option請(qǐng)求多了2個(gè)字段:
            //Access-Control-Request-Method:該次請(qǐng)求的請(qǐng)求方式
            //Access-Control-Request-Headers:該次請(qǐng)求的自定義請(qǐng)求頭字段
            //Access-Control-Max-Age 表明該響應(yīng)的有效時(shí)間為 86400 秒栗涂,也就是 24 小時(shí)。在有效時(shí)間內(nèi)祈争,瀏覽器無(wú)須為同一請(qǐng)求再次發(fā)起預(yù)檢請(qǐng)求斤程。請(qǐng)注意,瀏覽器自身維護(hù)了一個(gè)最大有效時(shí)間菩混,如果該首部字段的值超過(guò)了最大有效時(shí)間忿墅,將不會(huì)生效
            //預(yù)檢結(jié)果緩存時(shí)間,也就是上面說(shuō)到的緩存啦
            //'Access-Control-Max-Age: 86400'
          
            header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); //允許的請(qǐng)求類型
            
            header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept"); // 允許的請(qǐng)求頭字段
        }

        if (Request::isOptions()) { // 判斷是否為OPTIONS請(qǐng)求
            exit; //因?yàn)轭A(yù)檢請(qǐng)求第一次是發(fā)送OPTIONS請(qǐng)求返回了響應(yīng)頭的內(nèi)容,但沒(méi)有返回響應(yīng)實(shí)體response body內(nèi)容沮峡。這個(gè)我們不處理業(yè)務(wù)邏輯疚脐,第二次接收的get或post等才是實(shí)質(zhì)的請(qǐng)求返回我們才處理
        }
 }   

三、nginx反向代理

nginx是一種高性能的反向代理服務(wù)器
nginx拿到客戶端的請(qǐng)求邢疙,將請(qǐng)求轉(zhuǎn)發(fā)給其他的服務(wù)器棍弄,處理完成后返回給nginx望薄,nginx服務(wù)器會(huì)交給客戶端,主要的場(chǎng)景是維持服務(wù)器集群的負(fù)載均衡呼畸。

server {
  listen  80;
  server_name  local.test;
  location /api {
    proxy_pass http://localhost:8080;
  }
}

當(dāng)客戶訪問(wèn)local.test/api的時(shí)候痕支,nginx會(huì)將服務(wù)轉(zhuǎn)發(fā)到http://localhost:8080上,當(dāng)相應(yīng)返回后蛮原,將相應(yīng)內(nèi)容發(fā)給客戶端

四卧须、webpack中的proxy代理

 proxy: { //代理
            '/api': {
                target: 'http://localhost:3000',
            },
        }

當(dāng)訪問(wèn)/api/xxx的時(shí)候,會(huì)轉(zhuǎn)向訪問(wèn)http://localhost:3000/xxx

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末儒陨,一起剝皮案震驚了整個(gè)濱河市花嘶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蹦漠,老刑警劉巖椭员,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異笛园,居然都是意外死亡隘击,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門喘沿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)闸度,“玉大人竭贩,你說(shuō)我怎么就攤上這事蚜印。” “怎么了留量?”我有些...
    開(kāi)封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵窄赋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我楼熄,道長(zhǎng)忆绰,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任可岂,我火速辦了婚禮错敢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缕粹。我一直安慰自己稚茅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布平斩。 她就那樣靜靜地躺著亚享,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绘面。 梳的紋絲不亂的頭發(fā)上欺税,一...
    開(kāi)封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天侈沪,我揣著相機(jī)與錄音,去河邊找鬼晚凿。 笑死亭罪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晃虫。 我是一名探鬼主播皆撩,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼哲银!你這毒婦竟也來(lái)了扛吞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤荆责,失蹤者是張志新(化名)和其女友劉穎滥比,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體做院,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盲泛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了键耕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺滚。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖屈雄,靈堂內(nèi)的尸體忽然破棺而出村视,到底是詐尸還是另有隱情,我是刑警寧澤酒奶,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布蚁孔,位于F島的核電站,受9級(jí)特大地震影響惋嚎,放射性物質(zhì)發(fā)生泄漏杠氢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一另伍、第九天 我趴在偏房一處隱蔽的房頂上張望鼻百。 院中可真熱鬧,春花似錦摆尝、人聲如沸温艇。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)中贝。三九已至,卻和暖如春臼朗,著一層夾襖步出監(jiān)牢的瞬間邻寿,已是汗流浹背蝎土。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绣否,地道東北人誊涯。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蒜撮,于是被迫代替她去往敵國(guó)和親暴构。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

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