用nginx的反向代理機制解決前端跨域問題在nginx上部署web靜態頁面
1.什么是跨域以及產生原因
跨域是指a頁面想獲取b頁面資源,如果a、b頁面的協議、域名、端口、子域名不同,或是a頁面為ip地址,b頁面為域名地址,所進行的訪問行動都是跨域的,而瀏覽器為了安全問題一般都限制了跨域訪問,也就是不允許跨域請求資源。
跨域情況如下:
url | 說明 | 是否跨域 |
http://www.cnblogs.com/a.js http://www.a.com/b.js |
不同域名 | 是 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js |
同一域名下不同文件夾 | 否 |
http://www.a.com:8000/a.js http://www.a.com/b.js |
同一域名,不同端口 | 是 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名,不同協議 | 是 |
http://www.a.com/a.js http://70.32.92.74/b.js |
域名和域名對應ip | 是 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同,子域不同 | 是(cookie不可訪問) |
http://www.a.com/a.js http://a.com/b.js |
同一域名,不同二級域名(同上) | 是 |
2.跨域的常見解決方法
目前來講沒有不依靠服務器端來跨域請求資源的技術
1.jsonp 需要目標服務器配合一個callback函數。
2.window.name+iframe 需要目標服務器響應window.name。
3.window.location.hash+iframe 同樣需要目標服務器作處理。
4.html5的 postMessage+ifrme 這個也是需要目標服務器或者說是目標頁面寫一個postMessage,主要側重於前端通訊。
5.CORS 需要服務器設置header :Access-Control-Allow-Origin。
6.nginx反向代理 這個方法一般很少有人提及,但是他可以不用目標服務器配合,不過需要你搭建一個中轉nginx服務器,用於轉發請求。
3.nginx反向代理解決跨域
上面已經說到,禁止跨域問題其實是瀏覽器的一種安全行為,而現在的大多數解決方案都是用標簽可以跨域訪問的這個漏洞或者是技巧去完成,但都少不了目標服務器做相應的改變,而我最近遇到了一個需求是,目標服務器不能給予我一個header,更不可以改變代碼返回個script,所以前5種方案都被我否決掉。最后因為我的網站是我自己的主機,所以我決定搭建一個nginx並把相應代碼部署在它的下面,由頁面請求本域名的一個地址,轉由nginx代理處理后返回結果給頁面,而且這一切都是同步的。
關於nginx的一些基本配置和安裝請看我的另一篇博客,下面直接講解如何配置一個反向代理。
首先找到nginx.conf或者nginx.conf.default 或者是default里面的這部份
其中server代表啟動的一個服務,location 是一個定位規則。
1
2
3
4
5
6
7
|
location /{ #所有以/開頭的地址,實際上是所有請求
root html #去請求../html文件夾里的文件,其中..的路徑在nginx里面有定義,安裝的時候會有默認路徑,詳見另一篇博客
index index.html index.htm #首頁響應地址
}
|
從上面可以看出location是nginx用來路由的入口,所以我們接下來要在location里面完成我們的反向代理。
假如我們我們是www.a.com/html/msg.html 想請求www.b.com/api/?method=1¶=2;
我們的ajax:
1
2
3
4
5
6
7
|
var
url = 'http://www.b.com/api/msg?method=1¶=2' ;
<br>$.ajax({
type:
"GET"
,
url:url,
success:
function
(res){..},
....
})
|
上面的請求必然會遇到跨域問題,這時我們需要修改一下我們的請求url,讓請求發在nginx的一個url下。
1
2
3
4
5
6
7
8
9
|
var
url = 'http://www.b.com/api/msg?method=1¶=2' ;
var
proxyurl = 'msg?method=1¶=2' ;
//假如實際地址是 www.c.com/proxy/html/api/msg?method=1¶=2; www.c.com是nginx主機地址
$.ajax({
type:
"GET"
,
url:proxyurl,
success:
function
(res){..},
....
})
|
再在剛才的路徑中匹配到這個請求,我們在location下面再添加一個location。
1
2
3
4
|
location ^~/proxy/html/{
rewrite ^/proxy/html/(.*)$ /$1
break
;
proxy_pass http:
//www.b.com/;
}
|
以下做一個解釋:
1.'^~ /proxy/html/ '
就像上面說的一樣是一個匹配規則,用於攔截請求,匹配任何以 /proxy/html/開頭的地址,匹配符合以后,停止往下搜索正則。
2.rewrite ^/proxy/html/(.*)$ /$1 break;
代表重寫攔截進來的請求,並且只能對域名后邊的除去傳遞的參數外的字符串起作用,例如www.c.com/proxy/html/api/msg?method=1¶=2重寫。只對/proxy/html/api/msg重寫。
rewrite后面的參數是一個簡單的正則 ^/proxy/html/(.*)$ ,$1代表正則中的第一個(),$2代表第二個()的值,以此類推。
break代表匹配一個之后停止匹配。
3.proxy_pass
既是把請求代理到其他主機,其中 http://www.b.com/ 寫法和 http://www.b.com寫法的區別如下:
不帶/
1
2
3
4
|
location /html/
{
proxy_pass http:
//b.com:8300;
}
|
帶/
1
2
3
4
|
location /html/
{
proxy_pass http:
//b.com:8300/;
}
|
上面兩種配置,區別只在於proxy_pass轉發的路徑后是否帶 “/”。
針對情況1,如果訪問url = http://server/html/test.jsp,則被nginx代理后,請求路徑會便問http://proxy_pass/html/test.jsp,將test/ 作為根路徑,請求test/路徑下的資源。
針對情況2,如果訪問url = http://server/html/test.jsp,則被nginx代理后,請求路徑會變為 http://proxy_pass/test.jsp,直接訪問server的根資源。
修改配置后重啟nginx代理就成功了。
1.mac使用ssh命令登陸遠程主機
因為蘋果mac os x自帶ssh命令,所以我們只需打開終端輸入
1
|
$ ssh user@remote
|
在這之前最好在服務器上上傳自己的ssh key,避免每次登陸輸入密碼
稍作等待就連接上服務器了
2.mac使用scp命令向遠處主機上傳文件
在終端窗口,按下command+n,打開另一個終端窗口,並輸入
1
|
$ scp ~/local/file user@remote:~/file
|
當然一般我們上傳的是文件夾,所以加上-r
1
|
$ scp -r ~/local/file user@remote:~/file
|
3.nginx安裝與配置
首先檢查一下遠程服務器是否安裝ngnix.
1
|
nginx -V
|
因為博主的服務器已經安裝ngnix,所以下面介紹一下mac os x系統安裝nginx的方法
首先我們要用到homebrew,在終端中輸入
1
|
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
等待安裝結束。
再在終端執行,等待安裝結束皆可
1
|
brew install nginx
|
brew常用命令:
安裝軟件: brew install *(軟件名 eg. brew install nginx)
卸載軟件: brew uninstall *
搜索軟件: brew search *
顯示已經安裝軟件列表: brew list
更新軟件: brew update
更新某具體軟件: brew upgrade git
接下來主要是nginx的配置問題,因為nginx的配置項較多,這里就不一一介紹,只把運行一個靜態頁面需要配置的東西拿出來配置一下
首先可以看一下nginx的默認配置,可通過brew查看
從上圖中可以看到,nginx的默認root路徑(也就是服務器根目錄)是 /usr/local/var/www
默認端口:8080
下面進入nginx的配置文件,我們也能看到這些信息.
nginx的配置文件是nginx.conf和nginx.conf.default,一般我們可以從
/usr/local/etc/nginx/ 中找到這兩個文件,通過vim打開nginx.conf。
可以在配置中看到這樣一段,可以在location的root 中改變文件存放位置
注意:此處有個大坑
默認路徑事 /usr/local/var/www,而在配置中又寫了root html,所以真是路徑是 /usr/local/var/www/html
但我們cd 進入/usr/local/var/www 並沒有html文件,所以需要手動創建一個html,並放入工程。
如果發現nginx沒有加載到某些文件或是某些頁面出現一下403錯誤,是因為沒有權限
輸入 chmod 755 問題文件路徑就可以解決
修改之后需要停止nginx重新啟動:終端輸入
nginx -s stop 停止 nginx 重啟
4.mac使用cp命令把web文件復制到nginx的路由地址文件
在上一步我們已經知道了 /usr/local/var/www 是系統運行的根目錄,那么我們使用cp命令把我們的本地文件復制到此處
1
|
cp -r /local/files /des/files
|
5.瀏覽工程