跨域是指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.jshttps://www.a.com/b.js
| 同一域名,不同協定 | 是 |
http://www.a.com/a.jshttp://70.32.92.74/b.js
| 網域與網域對應ip | 是 |
http://www.a.com/a.jshttp://script.a.com/b.js
| 主網域相同,子網域不同 | 是(cookie不可存取) |
#http://www.a.com/a.jshttp:// a.com/b.js
| 同一域名,不同二級域名(同上) | 是 |
#跨域的常見解決方法
目前來講沒有不依賴伺服器端來跨網域請求資源的技術
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伺服器,用於轉發請求。
nginx反向代理解決跨域
上面已經說到,禁止跨域問題其實是瀏覽器的一種安全行為,而現在的大多數解決方案都是用標籤可以跨網域存取的這個漏洞或是技巧去完成,但都少不了目標伺服器做相應的改變,而我最近遇到了一個需求是,目標伺服器不能給我一個header,更不可以改變程式碼回傳個script,所以前5種方案都被我否決掉。最後因為我的網站是我自己的主機,所以我決定搭建一個nginx並把相應代碼部署在它的下面,由頁面請求本域名的一個地址,轉由nginx代理處理後返回結果給頁面,而且這一切都是同步的。
關於nginx的一些基本配置和安裝請看我的另一篇博客,下面直接講解如何配置一個反向代理。
先找到nginx.conf或nginx.conf.default 或default裡面的這部分
################### ## 其中server代表啟動的一個服務,location 是一個定位規則。 #########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:
var url = 'http://www.b.com/api/msg?method=1¶=2';
<br>$.ajax({
type: "GET",
url:url,
success: function(res){..},
....
})
登入後複製
上面的请求必然会遇到跨域问题,这时我们需要修改一下我们的请求url,让请求发在nginx的一个url下。
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。
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写法的区别如下:
不带/
location /html/
{
proxy_pass http://b.com:8300;
}
登入後複製
带/
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代理就成功了。