经典再续!《循序渐进Linux(第2版)

爱维Linux

 找回密码
 加入爱维Linux

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: 活动 交友 discuz
查看: 1665|回复: 0

nginx跨域访问问题总结

[复制链接]

589

主题

705

帖子

15

精华

爱维管理员

Rank: 9Rank: 9Rank: 9

积分
2857
发表于 2017-5-12 11:03:54 | 显示全部楼层 |阅读模式

马上加入爱维网,一起交流运维经验!

您需要 登录 才可以下载或查看,没有帐号?加入爱维Linux

x
一、什么是跨域

简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。

同源是指相同的协议、域名、端口。特别注意两点:

  • 如果是协议和端口造成的跨域问题“前台”是无能为力的,
  • 在跨域问题上,域仅仅是通过“协议+域名+端口”来识别,两个不同的域名即便指向同一个ip地址,也是跨域的。
二、常见跨域情况:
URL说明是否允许通信
http://www.a.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
主域相同,子域不同不允许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上)不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不同域名不允许


特别注意两点:第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。


三、跨域解决方案有多种,大多是利用JS Hack


  • document.domain+iframe的设置
  • 动态创建script
  • 利用iframe和location.hash
  • window.name实现的跨域数据传输
  • 使用HTML5 postMessage
  • 利用flash  以上方案见http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html#m5
  • nginx反向代理 这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求。
  • Jquery JSONP(本质上就是动态创建script)http://www.cnblogs.com/chopper/archive/2012/03/24/2403945.html
  • 跨域资源共享(CORS) 这就是我们要介绍的跨域解决方案,也是未来的跨域问题的标准解决方案

四、关于CORS


CORS: 跨域资源共享(Cross-Origin Resource Sharing)http://www.w3.org/TR/cors/
当前几乎所有的浏览器(Internet Explorer 8+, Firefox 3.5+, Safari 4+和 Chrome 3+)都可通过名为跨域资源共享(Cross-Origin Resource Sharing)的协议支持ajax跨域调用。(see: http://caniuse.com/#search=cors)

Chrome, Firefox, Opera and Safari 都使用的是 XMLHttpRequest2 对象, IE使用XDomainRequest。XMLHttpRequest2的Request属性:open()、setRequestHeader()、timeout、withCredentials、upload、send()、send()、abort()。

XMLHttpRequest2的Response属性:status、statusText、getResponseHeader()、getAllResponseHeaders()、entity、overrideMimeType()、responseType、response、responseText、responseXML。

1、启用 CORS 请求
假设您的应用已经在 example.com 上了,而您想要从 www.example2.com 提取数据。一般情况下,如果您尝试进行这种类型的 AJAX 调用,请求将会失败,而浏览器将会出现“源不匹配”的错误。利用 CORS,www.example2.com 服务端只需添加一个HTTP Response头,就可以允许来自 example.com 的请求:
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Credentials: true(可选)
可将 Access-Control-Allow-Origin 添加到某网站下或整个域中的单个资源。要允许任何域向您提交请求,请设置如下:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true(可选)
其实,该网站 (html5rocks.com) 已在其所有网页上均启用了 CORS。启用开发人员工具后,您就会在我们的响应中看到 Access-Control-Allow-Origin 了。

2、CORS方法实现跨域请求


要实现CORS跨域,服务端需要这个一个流程:http://www.html5rocks.com/static/images/cors_server_flowchart.png
对于简单请求,如GET,只需要在HTTP Response后添加Access-Control-Allow-Origin。
对于非简单请求,比如POST、PUT、DELETE等,浏览器会分两次应答。第一次preflight(method: OPTIONS),主要验证来源是否合法,并返回允许的Header等。第二次才是真正的HTTP应答。所以服务器必须处理OPTIONS应答。

http://enable-cors.org/server_nginx.html 这里是一个nginx启用COSR的参考配置。

流程如下:

  • 首先查看http头部有无origin字段;
  • 如果没有,或者不允许,直接当成普通请求处理,结束;
  • 如果有并且是允许的,那么再看是否是preflight(method=OPTIONS);
  • 如果是preflight,就返回Allow-Headers、Allow-Methods等,内容为空;
  • 如果不是preflight,就返回Allow-Origin、Allow-Credentials等,并返回正常内容。


首先,在远端需要访问的主机上做设置,假如远端主机是nginx服务,那么添加如下信息即可。


  1. server {
  2. listen 80;
  3. server_name tangxiaoyue.com;
  4. if ( $http_user_agent = "Mozilla/5.0"){
  5. return 403;
  6. }
  7. location / {
  8. <b>add_header 'Access-Control-Allow-Origin' '*';
  9. add_header 'Access-Control-Allow-Credentials' 'true';
  10. add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
  11. # Custom headers and headers various browsers *should* be OK with but aren't
  12. add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';</b>
  13. 后面省略。。。
  14. }
  15. }
复制代码

五、nginx反向代理解决跨域
    禁止跨域问题其实是浏览器的一种安全行为,而现在的大多数解决方案都是用标签可以跨域访问的这个漏洞或者是技巧去完成,但都少不了目标服务器做相应的改变,如果目标服务器无法改变的时候,就需要本地服务器实现,本地实现的话,需要搭建一个nginx并把相应代码部署在它的下面,由页面请求本域名的一个地址,转由nginx代理到目标服务器处理后返回结果给页面,而且这一切都是同步的。

假如代理服务器地址是 www.c.com/proxy/html/api/msg?method=1¶=2;   www.c.com是nginx主机地址
远端服务器地址:http://www.b.com/api/msg?method=1¶=2

在nginx服务器上做如下配置
在location下面再添加一个location。




location ^~/proxy/html/{
rewrite ^/proxy/html/(.*)$ /$1 break;
}
以下做一个解释:
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代表匹配一个之后停止匹配。





回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入爱维Linux

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|Archiver|手机版|小黑屋|爱维教育 ( 14004819

GMT+8, 2019-7-22 17:58 , Processed in 0.063395 second(s), 29 queries .

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表