PHP跨域方法用Nginx 反向代理
2021-05-22
什么是跨域
跨域,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對(duì)javascript施加的安全限制。
所謂同源是指,域名,協(xié)議,端口相同。瀏覽器執(zhí)行javascript腳本時(shí),會(huì)檢查這個(gè)腳本屬于那個(gè)頁(yè)面,如果不是同源頁(yè)面,就不會(huì)被執(zhí)行。
同源策略的目的,是防止黑客做一些做奸犯科的勾當(dāng)。比如說(shuō),如果一個(gè)銀行的一個(gè)應(yīng)用允許用戶上傳網(wǎng)頁(yè),如果沒(méi)有同源策略,黑客可以編寫一個(gè)登陸表單提交到自己的服務(wù)器上,得到一個(gè)看上去相當(dāng)高大上的頁(yè)面。黑客把這個(gè)頁(yè)面通過(guò)郵件等發(fā)給用戶,用戶誤認(rèn)為這是某銀行的主網(wǎng)頁(yè)進(jìn)行登陸,就會(huì)泄露自己的用戶數(shù)據(jù)。而因?yàn)闉g覽器的同源策略,黑客無(wú)法收到表單數(shù)據(jù)。
現(xiàn)在隨著RESTFUL的流行,很多應(yīng)用提供http/https接口的API,通過(guò)xml/json格式對(duì)外提供服務(wù),實(shí)現(xiàn)開(kāi)放架構(gòu)。如,微博、微信、天氣預(yù)報(bào)、openstack等網(wǎng)站和應(yīng)用都提供restful接口。
Web應(yīng)用也在向單頁(yè)面方向發(fā)展。越來(lái)越多的web應(yīng)用現(xiàn)在是這樣的架構(gòu):
靜態(tài)單個(gè)web頁(yè)面
ajax調(diào)用
RESTFUL服務(wù)
我們本可以利用各個(gè)網(wǎng)站提供的API,做出很多精彩的Web應(yīng)用。但瀏覽器執(zhí)行javascript時(shí)的跨域限制,就成為了這類開(kāi)放架構(gòu)的攔路虎。
本文提出了一種簡(jiǎn)單有效的方式解決跨域問(wèn)題。
常用的跨域方法
常用的跨域方法有這樣一些:
1,使用iFrame訪問(wèn)另一個(gè)域。然后再?gòu)牧硪粋€(gè)頁(yè)面讀取iFrame的內(nèi)容。jquery等有一些封裝。據(jù)說(shuō)Firefox等可能不支持讀取另一個(gè)iFrame的內(nèi)容。
2,jsonp。需要服務(wù)器支持。使用script src動(dòng)態(tài)得到一段java代碼。是回調(diào)頁(yè)面上的js函數(shù),參數(shù)是一個(gè)json對(duì)象。jquery也有封裝。
3,設(shè)置http頭,Access-Control-Allow-Origin:*但據(jù)說(shuō)IE有一些版本不識(shí)別這個(gè)http頭。
4,服務(wù)器代理。如,服務(wù)器寫一個(gè)url的處理action。其參數(shù)是一個(gè)url。這個(gè)服務(wù)器會(huì)用參數(shù)拼湊一個(gè)url,用httpclient庫(kù)去執(zhí)行url,然后把讀取的內(nèi)容再輸出到http客戶端。
nginx反向代理實(shí)現(xiàn)跨域
上面提到的這些跨域方法,都有一些問(wèn)題。有的不能支持所有瀏覽器,有的需要修改javascript代碼,有的需要重寫服務(wù)器端代碼。有的在session等場(chǎng)景下會(huì)有問(wèn)題。
其實(shí),用nginx反向代理實(shí)現(xiàn)跨域,是最簡(jiǎn)單的跨域方式。只需要修改nginx的配置即可解決跨域問(wèn)題,支持所有瀏覽器,支持session,不需要修改任何代碼,并且不會(huì)影響服務(wù)器性能。
我 們只需要配置nginx,在一個(gè)服務(wù)器上配置多個(gè)前綴來(lái)轉(zhuǎn)發(fā)http/https請(qǐng)求到多個(gè)真實(shí)的服務(wù)器即可。這樣,這個(gè)服務(wù)器上所有url都是相同的域 名、協(xié)議和端口。因此,對(duì)于瀏覽器來(lái)說(shuō),這些url都是同源的,沒(méi)有跨域限制。而實(shí)際上,這些url實(shí)際上由物理服務(wù)器提供服務(wù)。這些服務(wù)器內(nèi)的 javascript可以跨域調(diào)用所有這些服務(wù)器上的url。
下面,給出一個(gè)nginx支持跨域的例子,進(jìn)行具體說(shuō)明。
如,我們有兩個(gè)pythonflask開(kāi)發(fā)的項(xiàng)目:testFlask1和testFlask2。
testFlask2項(xiàng)目上的javascript腳本要通過(guò)ajax方式調(diào)用testFlask1的一個(gè)url,獲取一些數(shù)據(jù)。
正常情況下部署,就會(huì)有跨域問(wèn)題,瀏覽器拒絕執(zhí)行如下這樣的調(diào)用。
$("button").click(function(){
$.get("127.0.0.1:8081/partners/json",
function(result){
$("div").html(result);
});
});
下面把testFlask2項(xiàng)目的javascrip文件修改一下。這樣訪問(wèn)同源的url,就不會(huì)有跨域問(wèn)題。
$("button").click(function(){
$.get("partners/json", function(result){
$("div").html(result);
});
});
但是,我們testFlask2項(xiàng)目實(shí)際上沒(méi)有partners/json這樣的url,那怎么處理呢?
我們這樣編寫nginx的配置文件:
server{
listen8000;
location/ {
includeuwsgi_params;
uwsgi_passunix:/tmp/testFlask2.sock;
}
location/partners {
rewrite^.+partners/?(.*)$ /$1 break;
includeuwsgi_params;
uwsgi_passunix:/tmp/testFlask1.sock;
}
}
我們把testFlask2項(xiàng)目部署在8080端口的根目錄下。把提供web服務(wù)的testFlask1項(xiàng)目部署在/partners目錄下。
但我們的testFlask1項(xiàng)目并不能處理/partners/json這樣的url請(qǐng)求。那怎么辦呢?
通過(guò) rewrite^.+partners/?(.*)$ /$1 break; 這一條命令,nginx可以把收到的/partners/*請(qǐng)求全部轉(zhuǎn)為/*請(qǐng)求后再轉(zhuǎn)發(fā)給背后的真實(shí)web服務(wù)器。
這樣,RESTFUL的ajax客戶端程序,只需要給出特定前綴的url就可以調(diào)用任意服務(wù)器提供的RESTFUL接口了。
甚至,通過(guò)nginx的反向代理,我們還能調(diào)用其他公司開(kāi)發(fā)的網(wǎng)站提供的RESTFUL接口。
如,
location/sohu {
rewrite^.+sohu/?(.*)$ /$1 break;
includeuwsgi_params;
proxy_passhttp://www.sohu.com/;
}
我們就把sohu網(wǎng)站整個(gè)搬到我們的8080:/sohu/目錄下了,我們的javascript就可以盡情調(diào)用其RESTFUL服務(wù)了。
順便說(shuō)一下,rewrite^.+sohu/?(.*)$ /$1 break; 這句命令中,$1表示(.*)這個(gè)部分。第一對(duì)()內(nèi)的參數(shù)是$1,第二對(duì)()內(nèi)的參數(shù)就是$2,以此類推。
總結(jié)
本文介紹了利用nginx的反向代理的功能,實(shí)現(xiàn)跨域訪問(wèn)任意應(yīng)用和網(wǎng)站的方法。
nginx是一個(gè)高性能的web服務(wù)器,常用作反向代理服務(wù)器。nginx作為反向代理服務(wù)器,就是把http請(qǐng)求轉(zhuǎn)發(fā)到另一個(gè)或者一些服務(wù)器上。
通過(guò)把本地一個(gè)url前綴映射到要跨域訪問(wèn)的web服務(wù)器上,就可以實(shí)現(xiàn)跨域訪問(wèn)。
對(duì)于瀏覽器來(lái)說(shuō),訪問(wèn)的就是同源服務(wù)器上的一個(gè)url。而nginx通過(guò)檢測(cè)url前綴,把http請(qǐng)求轉(zhuǎn)發(fā)到后面真實(shí)的物理服務(wù)器。并通過(guò)rewrite命令把前綴再去掉。這樣真實(shí)的服務(wù)器就可以正確處理請(qǐng)求,并且并不知道這個(gè)請(qǐng)求是來(lái)自代理服務(wù)器的。
簡(jiǎn)單說(shuō),nginx服務(wù)器欺騙了瀏覽器,讓它認(rèn)為這是同源調(diào)用,從而解決了瀏覽器的跨域問(wèn)題。又通過(guò)重寫url,欺騙了真實(shí)的服務(wù)器,讓它以為這個(gè)http請(qǐng)求是直接來(lái)自于用戶瀏覽器的。
這樣,為了解決跨域問(wèn)題,只需要?jiǎng)右幌耼ginx配置文件即可。簡(jiǎn)單、強(qiáng)大、高效!
*聲明:本文于網(wǎng)絡(luò)整理,版權(quán)歸原作者所有,如來(lái)源信息有誤或侵犯權(quán)益,請(qǐng)聯(lián)系我們刪除或授權(quán)事宜