怎么解决js跨域问题

86次阅读
没有评论

共计 3499 个字符,预计需要花费 9 分钟才能阅读完成。

这篇文章主要介绍怎么解决 js 跨域问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

Js 跨域问题是 web 开发人员最常碰到的一个问题之一。所谓 js 跨域问题,是指在一个域下的页面中通过 js 访问另一个不同域下的数据对象,出于安全性考 虑,几乎所有浏览器都不允许这种跨域访问,这就导致在一些 ajax 应用中,使用跨域的 web service 会成为一个问题。解决 js 跨域问题,目前在客户端和服务端都有一些现成的解决方案,但这些方案并不能解决所有问题。下面我们先来看下有哪些常用的解决方案,并针对空间产品 对跨域问题的需求给出一个 space 自己的解决方案,希望能对其他产品组有借鉴意义。
客户端解决方案
如何在客户端解决 js 跨域问题几乎是所有 web 开发人员会首先考虑的。目前最常用的方法有 2 种:设置 document.domain、通过 script 标签加载。
设置 document.domain
采用这种方法的前提是跨域请求涉及的两个页面必须属于一个基础域(例如都是 xxx.com,或是 xxx.com.cn),使用同一协议(例如都是 http)和同一端口(例如都是 80)。例如,aaa.xxx.com 里面的一个页面需要调用 bbb.xxx.com 里的一个对象,则将两个页面的 document.domain 都设置为 xxx.com,就可以实现跨域调用了。另外,需要注意的是,这种方式只能用在父、子页面之中,即只有在用 iframe 进行数据访问时才有用。
通过 script 标签加载
对于浏览器来说,script 标签的 src 属性所指向资源就跟 img 标签的 src 属性所指向的资源一样,都是一个静态资源,浏览器会在适当的时候自动去加 载这些资源,而不会出现所谓的跨域问题。这样我们就可以通过该属性将要访问的数据对象引用进当前页面而绕过 js 跨域问题。例如,在 space 的我的空间项目中,需要在 hi 域下管理中心页面中随机推荐几个热门模块给用户,由于热门模块的相关信息都在 act 域下的 php 模块中维 护,如果直接在 hi 域下通过 ajax 请求去获取 act 域下的推荐模块列表相关信息就出现 js 跨域问题。解决这个问题的最简单方法就是,在 hi 域下通过 script 标签去访问 act 域提供的这个 http 接口:
script type=”text/javascript”src=http://www.2cto.com/kf/201109/”http://act.hi.baidu.com/widget/recommend”script
当然,前提是 act 域的这个 http 接口必须是返回一段 js 脚本,如一个 json 对象数组定义的脚本:
modlist = [
{“modname”:“mod1”, “usernum”: 200,“url”:”/widget/info/1”},
{“modname”:”mod2”, “usernum”: 300,”url”:”/widget/info/2”},

];
但 script 标签也有一定的局限性,并不能解决所有 js 跨域问题。script 标签的 src 属性值不能动态改变以满足在不同条件下获取不同数据的需求,更重要的是,不能通过这种方式正确访问以 xml 内容方式组织的数据。
服务端解决方案
从上面的说明可以看到,客户端的解决方案局限性太大,而且对于 ajax 跨域请求,无论两个域是否属于同个基础域,都无法在客户端加以解决。也就是说,如果 我们要想在 ajax 请求中访问其他域下的数据,就只能通过服务端进行处理了。服务端的解决方案的基本原理就是,由客户端将请求发给本域服务器,再由本域服务器的代理来请求数据并将响应返回给客户端。最常用的服务器解决方案就是利用 web 服务器本身提供的 proxy 功能,如 apache 和 lighttpd 的 mod_proxy 模块。在百度内 部,transmit 的分流功能也可以解决部分跨域问题。但这些方法都有一定的局限性,鉴于安全性等问题的考虑,space 这边最后开发了一个专门用于处 理跨域请求代理服务的 spproxy 模块,用于彻底解决 js 跨域问题。下面我们将以空间的开放平台为例,简单介绍下如何通过 apache 的 mod_proxy、transmit 的分流以及 space 的 spproxy 模块来解 决该跨域问题,并简单介绍下 spproxy 的一些特性、缺点及下一步的改进计划。空间在展现每个 UWA 开放模块之前都必须请求该模块的 xml 源代码以进行解析,每个模块的源代码文件都是存放在 act 域下的 /ow/uwa 目录下,那么在 用户空间首页(hi 域)中请求该 xml 文件时就会存在 js 跨域问题。要解决该问题,只能让 js 向 hi 域的 web 服务器请求 xml 文件,而 hi 域 web 服务 器则通过一定的代理机制(如 mod_proxy、transmit 分流、spproxy)向 act 域的 web 服务器请求文件。
利用 apache 的 mod_proxy 模块
如果 apache 是 2.0 系列版本,则可以通过在 httpd.conf 文件中增加以下配置加以解决:
ProxyRequests  Off
Proxy *
Order deny,allow
Allow from all
/Proxy
ProxyPass  /ow/uwa  http://act.hi.baidu.com/ow/uwa
其中,ProxyRequests 指令关闭了 mod_proxy 的正向代理功能而启用反向代理功能,Proxy 指令使得该配置对所有访问生效,ProxyPass 指令使得对本域的 /ow /uwa 目录下的任何资源的访问都会在内部被转换为一个对 act.hi.baidu.com 域下的 /ow/uwa 目录下对应资源的代理请求。这样,js 就可以直接通过访问 http://hi.baidu.com/ow/uwa/0/1/0/10001.xml 获取位于 act 域下的 /ow/uwa/0/1/0/ 目录下的 10001.xml 文件。
如果 apache 是经过百度各产品线修改过的 1.3 版本,则需要 mod_proxy 和 mod_rewrite 模块一起配合来达到同样的目的。首先需要在 httpd.conf 中增加以下 Location 指令:
Location /ow/uwa
SetHandler proxy-server
order allow,deny
Allow from all
/Location
这样,对于本域下的 /ow/uwa 目录下的任何资源的访问都会首先由 proxy-server 这个 handler(mod_proxy 模块内部定义的一个 handler)来处理,但光有这段配置还不行,因为还不 proxy-server 还不知道应该怎么处理,仅仅知道需要自己处理而已。这时还需要在配置段中增加一个 rewrite 规则:
RewriteRule ^/ow/uwa/(.*)$  http://act.hi.baidu.com/ow/uwa/$1?%{QUERY_STRING} [P,L]
Rewrite 规则最后的[P,L] 表明该 rewrite 是通过 mod_proxy 代理过去,而不是通过外部重定向过去。如果去掉 P 标志,即采用以下 rewrite 规则:
RewriteRule ^/ow/uwa/(.*)$  http://act.hi.baidu.com/ow/uwa/$1?%{QUERY_STRING} [L]
则响应返回给客户端时标明的资源 uri 将是重定向后的 uri,在我们的例子中就是 act.hi.baidu.com 域的 uri,则浏览器仍然会出现 js 跨 域问题。以上只是对 apache 的 proxy 功能的简单应用,更好更强大的介绍可以参考资料【1】和【2】。Mod_proxy 虽然强大,但我们并没有用它来解决跨域问题。首先,要使用它必须要求我们的每台前端机器都能够访问外网,否则我们就只能将请求代理到其 中一台前端机器上(通过机器名做内网域名进行 rewrite 或代理),而这显然是不可取的,因为我们的一个域名通常由很多前端机器组成,只代理到其中一台 机器会导致该机器压力与其他机器相比很不均衡,甚至撑不住压力,而给所有前端机器都加访问外网权限又可能会存在一些安全性策略问题(具体原因不清楚,但 op 和 sa 显然是不会赞同这种做法)。其次,由于 apache 本身并没有很好的防 ddos*** 机制,一旦有人通过代理去 *** 目标域(比如说我们的竞争对手 的网站),则在目标域的 web 服务器上看来,*** 者就成了我们了,这样的事情发生时,我们就百口莫辩,跳进黄河也洗不清了。

以上是“怎么解决 js 跨域问题”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注丸趣 TV 行业资讯频道!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-25发表,共计3499字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)