成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

徹底弄懂跨域問題

CoorChice / 1226人閱讀

摘要:瀏覽器同源策略我們?yōu)楹我芯靠缬騿栴}因?yàn)闉g覽器的同源策略規(guī)定某域下的客戶端在沒明確授權(quán)的情況下,不能讀寫另一個(gè)域的資源。

跨域,老生常談的問題 簡(jiǎn)述

作為一只前端菜鳥,跨域方面只懂得JSONP和CORS,并未曾深入了解。但隨著春招越來(lái)越近,就算是菜鳥也要猛振翅膀。近幾日仔細(xì)研究了跨域問題,寫下這篇文章,希望對(duì)開發(fā)者們有所幫助。在讀本文前,希望您對(duì)以下知識(shí)略有了解。

瀏覽器同源策略

nodejs

iframe

docker, nginx

我們?yōu)楹我芯靠缬騿栴}

因?yàn)闉g覽器的同源策略規(guī)定某域下的客戶端在沒明確授權(quán)的情況下,不能讀寫另一個(gè)域的資源。而在實(shí)際開發(fā)中,前后端常常是相互分離的,并且前后端的項(xiàng)目部署也常常不在一個(gè)服務(wù)器內(nèi)或者在一個(gè)服務(wù)器的不同端口下。前端想要獲取后端的數(shù)據(jù),就必須發(fā)起請(qǐng)求,如果不做一些處理,就會(huì)受到瀏覽器同源策略的約束。后端可以收到請(qǐng)求并返回?cái)?shù)據(jù),但是前端無(wú)法收到數(shù)據(jù)。

為何瀏覽器會(huì)制定同源策略

之所以有同源策略,其中一個(gè)重要原因就是對(duì)cookie的保護(hù)。cookie 中存著sessionID 。黑客一旦獲取了sessionID,并且在有效期內(nèi),就可以登錄。當(dāng)我們?cè)L問了一個(gè)惡意網(wǎng)站 如果沒有同源策略 那么這個(gè)網(wǎng)站就能通過js 訪問document.cookie 得到用戶關(guān)于的各個(gè)網(wǎng)站的sessionID 其中可能有銀行網(wǎng)站 等等。通過已經(jīng)建立好的session連接進(jìn)行攻擊,比如CSRF攻擊。
這里需要服務(wù)端配合再舉個(gè)例子,現(xiàn)在我扮演壞人 我通過一個(gè)iframe 加載某寶的登錄頁(yè)面 等傻傻的用戶登錄我的網(wǎng)站的時(shí)候 我就把這個(gè)頁(yè)面彈出 用戶一看 阿里唉大公司 肯定安全 就屁顛屁顛的輸入了密碼 注意 如果沒有同源策略 我這個(gè)惡意網(wǎng)站就能通過dom操作獲取到用戶輸入的值 從而控制該賬戶所以同源策略是絕對(duì)必要的.
還有需要注意的是同源策略無(wú)法完全防御CSRF。

多種跨域方法

跨域可以大概分為兩種目的

前后端分離時(shí),前端為了獲取后端數(shù)據(jù)而跨域

為不同域下的前端頁(yè)面通信而跨域

為前后端分離而跨域 Cross Origin Resource Share (CORS)

CORS是一個(gè)跨域資源共享方案,為了解決跨域問題,通過增加一系列請(qǐng)求頭和響應(yīng)頭,規(guī)范安全地進(jìn)行跨站數(shù)據(jù)傳輸

請(qǐng)求頭主要包括
請(qǐng)求頭 解釋
Origin Origin頭在跨域請(qǐng)求或預(yù)先請(qǐng)求中,標(biāo)明發(fā)起跨域請(qǐng)求的源域名。
Access-Control-Request-Method Access-Control-Request-Method頭用于表明跨域請(qǐng)求使用的實(shí)際HTTP方法
Access-Control-Request-Headers Access-Control-Request-Headers用于在預(yù)先請(qǐng)求時(shí),告知服務(wù)器要發(fā)起的跨域請(qǐng)求中會(huì)攜帶的請(qǐng)求頭信息
with-credentials 跨域請(qǐng)求攜帶cookie
響應(yīng)頭主要包括
響應(yīng)頭 解釋
Access-Control-Allow-Origin Access-Control-Allow-Origin頭中攜帶了服務(wù)器端驗(yàn)證后的允許的跨域請(qǐng)求域名,可以是一個(gè)具體的域名或是一個(gè)*(表示任意域名)。
Access-Control-Expose-Headers Access-Control-Expose-Headers頭用于允許返回給跨域請(qǐng)求的響應(yīng)頭列表,在列表中的響應(yīng)頭的內(nèi)容,才可以被瀏覽器訪問。
Access-Control-Max-Age Access-Control-Max-Age用于告知瀏覽器可以將預(yù)先檢查請(qǐng)求返回結(jié)果緩存的時(shí)間,在緩存有效期內(nèi),瀏覽器會(huì)使用緩存的預(yù)先檢查結(jié)果判斷是否發(fā)送跨域請(qǐng)求。
Access-Control-Allow-Methods Access-Control-Allow-Methods用于告知瀏覽器可以在實(shí)際發(fā)送跨域請(qǐng)求時(shí),可以支持的請(qǐng)求方法,可以是一個(gè)具體的方法列表或是一個(gè)*(表示任意方法)。
如何使用

客戶端只需按規(guī)范設(shè)置請(qǐng)求頭。

服務(wù)端按規(guī)范識(shí)別并返回對(duì)應(yīng)響應(yīng)頭,或者安裝相應(yīng)插件,修改相應(yīng)框架配置文件等。具體視服務(wù)端所用的語(yǔ)言和框架而定

SpringBoot 設(shè)置CORS例子

一個(gè)spring boot項(xiàng)目中關(guān)于CORS配置的一段代碼

HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String temp = request.getHeader("Origin");
        httpServletResponse.setHeader("Access-Control-Allow-Origin", temp);
        // 允許的訪問方法
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
//         Access-Control-Max-Age 用于 CORS 相關(guān)配置的緩存
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        httpServletResponse.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept,token");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
JSONP 跨域

jsonp的原理就是借助HTML中的

后端代碼(nodejs)

var querystring = require("querystring");
var http = require("http");
var server = http.createServer();

server.on("request", function(req, res) {
    var params = querystring.parse(req.url.split("?")[1]);
    var fn = params.callback;

    // jsonp返回設(shè)置
    res.writeHead(200, { "Content-Type": "text/javascript" });
    var data = {
        user: "xbc",
        password: "123456"
    }
    res.write(fn + "(" + JSON.stringify(data) + ")");

    res.end();
});

server.listen("8080");
console.log("Server is running at port 8080...");

在該例子中,前臺(tái)收到的res是這樣的

前端頁(yè)面是這樣的

注意

JSONP既是利用了,那么就只能支持GET請(qǐng)求。其他請(qǐng)求無(wú)法實(shí)現(xiàn)

nginx 反向代理實(shí)現(xiàn)跨域 思路

既然瀏覽器有同源策略限制,那我們把前端項(xiàng)目和前端要請(qǐng)求的api接口地址放在同源下不就可以了?再結(jié)合web服務(wù)器提供的反向代理,便可以在前端和后端都不做配置的情況下解決跨域問題。

以nginx為例

后端真實(shí)后臺(tái)地址:http://xxx.xxx.xxx.xxx:8085 后臺(tái)地址使用tomcat部署的spring boot項(xiàng)目 名為gsms_test

nginx服務(wù)器地址: http://xxx.xxx.xxx.xxx:8082

tomcat和nginx都是用docker架設(shè)的,做了端口轉(zhuǎn)發(fā)

使用條件:開發(fā)環(huán)境為linux系統(tǒng)

nginx /etc/nginx/conf.d/default.conf配置代碼如下

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        # root   /usr/share/nginx/html/dist; # 前端項(xiàng)目路徑
        # index  index.html index.htm;
        proxy_pass http://localhost:8001/; # 前端本機(jī)地址,實(shí)現(xiàn)自動(dòng)更新
        autoindex on;
        autoindex_exact_size on;
        autoindex_localtime on;
    }

    location /gsms_test/ {
        proxy_pass 后端真實(shí)地址;
    }

    

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ .php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ .php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache"s document root
    # concurs with nginx"s one
    #
    #location ~ /.ht {
    #    deny  all;
    #}
}

不同域下頁(yè)面通信而跨域 window.name + iframe 跨域

window.name是瀏覽器中一個(gè)窗口所共享的數(shù)據(jù),在不同的頁(yè)面(甚至不同域名)加載后依舊存在(如果沒修改則值不會(huì)變化),并且可以支持非常長(zhǎng)的 name 值(2MB)。比如 a域的某頁(yè)面想獲取b域某頁(yè)面的數(shù)據(jù),可以在b域中修改window.name值,a域切換到b域再切回來(lái)即可得到b域的window.name值??墒俏覀?cè)陂_發(fā)中肯定不想頁(yè)面切來(lái)切去,所以就要結(jié)合iframe來(lái)實(shí)現(xiàn)。

示例 (以thinkjs實(shí)現(xiàn))

a 域代碼如下





A 域


server A

b 域代碼





New ThinkJS Application


  

server 2

注意

由于受同源策略限制,父頁(yè)面獲取跨域的iframe頁(yè)面的信息不全,所以要在iframe的window.name被B域修改后,轉(zhuǎn)為A域下的任一頁(yè)面(該一面不得修改window.name),在進(jìn)行獲取。

代理頁(yè)面 + iframe 實(shí)現(xiàn)跨域訪問

由于iframe與父頁(yè)面相互訪問也受同源策略限制,所以要借助一代理頁(yè)面實(shí)現(xiàn)跨域。

個(gè)人認(rèn)為有些麻煩,若有興趣請(qǐng)看前端如何用代理頁(yè)面解決iframe跨域訪問的問題?

總結(jié)

以上幾種皆是本人用過或測(cè)試過的跨域方法,還有postMessage,WebSocket等跨域方法由于從未接觸不做說明。在項(xiàng)目中具體使用那些方法還需具體考慮各種問題

情況 方法
只有GET請(qǐng)求 JSONP
對(duì)兼容性及瀏覽器版本無(wú)要求 CORS
對(duì)兼容性及瀏覽器版本有要求 iframe 或 服務(wù)器反向代理(linux 環(huán)境下開發(fā))
本文參考

經(jīng)驗(yàn) 跨域方案

CORS——跨域請(qǐng)求那些事兒

前端如何用代理頁(yè)面解決iframe跨域訪問的問題?

前端常見的跨域解決方案(全)

CORS與服務(wù)器反向代理的優(yōu)劣對(duì)比

圖解正向代理、反向代理、透明代理

謝謝

本文如有錯(cuò)誤,歡迎指出
本人郵箱 [email protected]

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100975.html

相關(guān)文章

  • 徹底弄懂跨域問題

    摘要:用于告知瀏覽器可以將預(yù)先檢查請(qǐng)求返回結(jié)果緩存的時(shí)間,在緩存有效期內(nèi),瀏覽器會(huì)使用緩存的預(yù)先檢查結(jié)果判斷是否發(fā)送跨域請(qǐng)求。 跨域,老生常談的問題 簡(jiǎn)述 作為一只前端菜鳥,跨域方面只懂得JSONP和CORS,并未曾深入了解。但隨著春招越來(lái)越近,就算是菜鳥也要猛振翅膀。近幾日仔細(xì)研究了跨域問題,寫下這篇文章,希望對(duì)開發(fā)者們有所幫助。在讀本文前,希望您對(duì)以下知識(shí)略有了解。 瀏覽器同源策略 n...

    rose 評(píng)論0 收藏0
  • 一篇文章搞明白CORS跨域

    摘要:跨域?qū)嵲谑敲嬖嚬僖粋€(gè)人的利器。首先,什么是是一個(gè)標(biāo)準(zhǔn),全稱是跨域資源共享。它的值是一個(gè)布爾值,表示是否允許發(fā)送。設(shè)為,即表示服務(wù)器明確許可,可以包含在請(qǐng)求中,一起發(fā)給服務(wù)器。 面試問到數(shù)據(jù)交互的時(shí)候,經(jīng)常會(huì)問跨域如何處理。大部分人都會(huì)回答JSONP,然后面試官緊接著就會(huì)問:JSONP缺點(diǎn)是什么???這個(gè)時(shí)候坑就來(lái)了,如果面試者說它支持GET方式,然后面試官就會(huì)追問,那如果POST方式發(fā)送...

    tanglijun 評(píng)論0 收藏0
  • 前端經(jīng)典文章

    摘要:上周末看這篇文章時(shí),偶有靈光,所以,分享出來(lái)給大家一起看看前端面試四月二十家前端面試題分享請(qǐng)各位讀者添加一下作者的微信公眾號(hào),以后有新的文章,將在微信公眾號(hào)直接推送給各位,非常感謝。 前端切圖神器 avocode 有了這個(gè)神器,切圖再也腰不酸,腿不疼了。 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,...

    lowett 評(píng)論0 收藏0
  • 徹底弄懂JS中閉包

    閉包概念:   閉包就是有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù). 分析這句話:   1.閉包是定義在函數(shù)中的函數(shù).  2.閉包能訪問包含函數(shù)的變量.  3.即使包含函數(shù)執(zhí)行完了, 被閉包引用的變量也得不到釋放. 例子分析-1: function add(){ var i = 0 arr = []; ...

    DevYK 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<