`
落地窗
  • 浏览: 438284 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

解决js跨域问题 .

阅读更多

转载---如何解决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://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服务器上看来,攻击者就成了我们了,这样的事情发生时,我们就百口莫辩,跳进黄河也洗不清了。

利用transmit分流方案
用过transmit的产品线应该都知道,transmit除了用于防攻击之外,还有一个很重要的功能就是分流。有了分流功能,我们就可以将对特定 url 的访问分发给不同的apache处理,从而实现跨域访问的目的。 还是以空间开放平台的这个例子为例,假设我们的act域在jx机房内由jx-space-act00.jx和jx-space-act01.jx这两台机 器组成,apache的端口为8080,则只要我们在transmit的配置文件transmit_common.conf中增加以下配置:

PP_APACHE_DIR    :   /ow/uwa/
PP_APACHE0      :   jx-space-act00.jx:8080
PP_APACHE1      :   jx-space-act01.jx:8080则重启transmit后,南方用户就可以通过访问http://hi.baidu.com/ow/uwa/0/1/0/10001.xml 而获取http://act.hi.baidu.com/ow/uwa/0/1/0/10001.xml这个url所执行的xml内容,从而解决跨域问 题。如果我们在hi域下的js同时还想异步获取act域下的其他数据,比如说/sys/widget/xxx接口提供的数据,则只需要在 PP_APACHE_DIR配置项中增加一个目录定义:

PP_APACHE_DIR    :   /ow/uwa/, /sys/widget/由于旧版本的transmit只支持一个分流,所以不能通过它来同时解决对多个外域的跨域请求问题,同时,要支持旧版本transmit,后端的 apache需要做相应的代码修改和配置才行,这也限制了我们的分流功能不能解决跨非百度域的跨域问题。不过好消息是,gm最近发布的新版本 transmit允许增加n个分流,同时支持后端apache不做任何修改,那么对于旧版本transmit所碰到的限制也就不再存在了,通过它就可以在 一定程度上很好地解决跨域问题了。具体配置方法与旧版本类似,大家可以参考新版本transmit的配置文件做相应修改来实现这个目的。

利用spproxy模块
但是,在space的开放平台系统中,我们并不是通过transmit来解决跨域问题,前面也提到了,transmit只能在一定程度上解决这个问 题。为 什么这么说呢?由于transmit增加分流是需要在修改配置后重启transmit程序的,而且随着分流分支的增加,其性能会不断降低,毕竟每次请求到 来时它都需要遍历所有分流分支以判断应该走哪条分支,而对于开放平台来说,任何一个新的开放模块都有可能会引入一个甚至多个新的外域,这会导致 transmit的分流分支数随着开放模块数量的增加而线性增加,这无论在op运维上还是程序性能上都将是不可接受的。 基于这样的考虑,space在开放平台二期项目中引入了一个新的模块——spproxy模块,用于提供跨域请求代理服务,从而彻底解决了js跨域问题。 从某种意义上讲,spproxy其实就是一个ui,它接收来自apache的请求,并处理该请求获取真正的页面数据,然后返回给apache,再由 apache返回给客户端。Spproxy只接收一个apache命令号(AC_SYS_PROXY : 38),并提供了两个http接口:

/sys/pxy/ajax?url=xxxx和/sys/pxy/xml?url=xxx其中,/sys/pxy/是可以通过apache配置文件来修改成其他目录名的,url参数就是js希望跨域请求的数据的uri(需要进行url编 码,如 果url中有参数),xml接口与ajax接口的唯一区别是,spproxy会强制将前者返回的内容的Content-Type设为text/xml,而 对于后者,则是外域服务器返回的是何种Content-Type就是何种type。 Apache端只需要增加以下两个配置就可以让spproxy来处理以上两个http接口的请求,当然,前提是所用的apache是经过ns改写过的 apache,目前主要是1.3版本的apache:

CmdNoMap   pxy      38
CmdHost      pxy     10.23.64.185 20540其中,pxy就是http接口中的第二个目录名,可以自定义,例如配置里如果写的是proxy,则http接口就是/sys/proxy /ajax?url=xxx和/sys/proxy/xml?url=xxx;38是spproxy能够处理的命令号,可以在编译时修改成其他 值;10.23.64.185 20540是spproxy所在机器的ip和spproxy的侦听端口。 通过以上配置后,hi域下的js就可以通过异步访问http://hi.baidu.com/sys/pxy/xml?url=http: //act.hi.baidu.com/ow/uwa/0/1/0/10001.xml来跨域访问http://act.hi.baidu.com/ow /uwa/0/1/0/10001.xml了。如果跨域访问的资源uri带参数,如http://act.hi.baidu.com/widget /recommend?num=6,则在访问时需要将参数值进行url编码,如http://hi.baidu.com/sys/pxy /xml?url=http%3A%2F %2Fact%2Ehi%2Ebaidu%2Ecom%2Fwidget%2Frecommend%3Fnum%3D6。

Spproxy介绍
Spproxy是一个基于epoll网络模型开发的单进程模块,包含一个数据抓取线程和定时加载线程:  抓取线程 ,对跨域请求进行代理,抓取指定url对应的页面内容并返回给前端,此线程采用epoll模型提高请求处理的并发度  定时加载线程,定时加载域名白名单以及部分可重加载的配置项(如各种超时时间、是否强制指定cache过期时间等) spproxy通过一个域名白名单限制js能够跨域访问的域名以降低安全风险,需要增加一个js能够跨域访问的外域时只需要在spproxy的域名白名单 文件spproxy_domainlist.txt中增加一行即可,5分钟后(具体生效时间可配置)即会生效。 由于采用的是epoll网络模型,spproxy本身能够很好地抵御慢连接攻击,同时,它还具有与space ui同样强大的防攻击功能。 为了减少对外域服务器的请求以提高跨域请求的响应速度,同时又降低外域服务器封杀我们的代理服务的风险,spproxy本身做了一个相对简单的cache 功能。如果外域服务器返回的页面http头中指定了cache过期时间,spproxy就会根据该http头对该页面的cache过期时间算一个比较合理 的过期值并对页面进行cache;如果外域服务器返回的http头中没有指定cache过期时间或要求不进行cache,则spproxy还是会对该页面 进行短期的cache,过期时间可配置。 另外,对于spproxy模块中涉及的大多数超时时间配置及域名白名单都是可以定时重加载的,从而实现线上服务调整参数、增加信任域时无需重启服务作废 cache的目的。 不过,spproxy目前也还存在一些缺点:  返回给spproxy的响应体不能是经过压缩编码的,spproxy在向外域请求时会在http头中标明这一点,这会增加读响应时间和外域网站的带宽消耗  Spproxy目前只是根据外域服务器的http响应头中的Cache-Control字段中的max-age属性计算页面的cache过期时间,而实际 上很多网站返回的cache-control字段并不是通过max-age来标示cache过期时间的  Spproxy目前只支持GET方法,不支持其他http方法,而且,spproxy不支持任意大小的外域页面,但可以通过配置改变它所能接收的页面数据 量的最大值 下一步,spproxy将会在解析http响应头中的cache-control字段方面做些改进以便更加合理地控制spproxy对返回页面的 cache,另外,下一步还将支持通过POST方法进行跨域请求,以提高跨域请求的安全性。

参考资料
【1】 http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_proxy.html

【2】 http://lamp.linux.gov.cn/Apache/ApacheMenu/rewrite/rewrite_guide.html
分享到:
评论

相关推荐

    JSP使用ajaxFileUpload.js实现跨域问题.docx

    本文主要介绍如何在JSP项目中使用`ajaxFileUpload.js`插件解决跨域文件上传的问题,并提供了一个具体的示例代码,包括前端JS部分以及后端JSP和Struts2相关的处理逻辑。通过这个例子,我们可以深入了解整个跨域文件...

    pdf.js,内含跨域解决办法

    为了解决跨域问题,PDF.js 提供了几种解决方案: 1. 服务器端配置:在服务器端设置 CORS 头部,允许来自其他域的请求。例如,在 Apache 或 Nginx 配置中添加 `Access-Control-Allow-Origin` 头,指定允许访问的源...

    真正解决百度编辑器UEditor上传图片跨域问题.docx

    在尝试解决跨域问题时,开发者首先尝试了直接引用webuploader.js并对其进行调试,但没有成功。接着,开发者转向使用jQuery的ajax方法进行文件上传,因为jQuery提供了更方便的跨域支持。 在jQuery的ajax方法中,设置...

    doc解决跨域问题.pdf

    "doc解决跨域问题.pdf"文档中介绍的是如何在基于Koa的后端项目中处理这个问题。Koa是一个由Express.js作者创建的现代JavaScript Web框架,它提供了一种更简洁的方式来处理HTTP请求。 首先,项目初始化是必要的,这...

    js -- 跨域问题.doc

    跨域问题解决方案综述 跨域问题是指由于浏览器同源策略的限制,导致不同域之间的资源无法交互的现象。该问题在Web开发中非常常见,不仅会导致开发困难,也会影响用户体验。因此,了解跨域问题的解决方法非常重要。...

    js跨域问题解决方案.

    本文将深入探讨JavaScript跨域问题的原因、影响以及多种解决方案,帮助开发者理解和解决这个问题。 ### 1. 同源策略 同源策略是浏览器为了安全考虑而实施的一项机制,它规定了只有相同协议(http、https等)、相同...

    javascript插件 解决双向跨域问题

    jcrossdomain是一个专门用于解决JavaScript跨域问题的工具,尤其适用于需要双向通信的场景。它通过创建隐藏的IFrame和利用window.postMessage API来实现跨域通信。window.postMessage是HTML5引入的一个API,允许来自...

    利用动态创建script技术解决静态网站跨域问题.pdf

    解决静态网站跨域问题的动态创建Script技术 本文介绍了一种解决静态网站跨域问题的技术,即利用动态创建Script技术。该技术可以解决静态网站在跨域访问时的安全隐患问题。 动态创建Script技术是指在客户端生成...

    跨域demo.rar

    - **解决后端跨域**:在Node.js、Java、Python等后端服务中设置CORS头部,例如在Express中使用`app.use(cors())`。 - **前端跨域配置**:在React、Vue、Angular等前端框架中,可以使用axios等库,配置跨域请求。 ...

    【JavaScript源代码】解决vue $http的get和post请求跨域问题.docx

    本文将详细介绍如何解决 Vue.js 中使用 Axios (旧版本中称为 `$http`) 进行GET和POST请求时的跨域问题。 首先,我们需要理解什么是跨域。跨域是指浏览器阻止了一个源的文档或脚本尝试与另一个源交互的情况。这是...

    pdf.js 跨域版本

    跨域问题通常在 JavaScript 中是个常见的安全限制,浏览器不允许脚本从一个源(域名、协议或端口)请求另一个源的资源,以防止恶意网站通过脚本读取其他网站的数据。在 PDF.js 原版中,如果 PDF 文件存储在与网页...

    arcgis js跨域解决策略

    通过以上策略,你可以成功地在.NET或Java环境下解决arcgis js的跨域问题,确保GIS应用的正常运行。不过,需要注意的是,跨域问题的解决方案应根据项目需求和安全性考虑进行选择,确保既能满足功能需求,又能保障数据...

    解决JQurey跨域问题$.get|$.post|$.getJSON等等统统可跨域

    本篇将详细介绍如何解决jQuery跨域问题,涉及的方法包括$.get、$.post和$.getJSON等。 首先,我们需要理解什么是跨域。同源策略是浏览器为保障安全而实施的一项机制,它规定JavaScript只能访问与当前页面同源(协议...

    解决跨域jar包.rar

    在Web开发中,跨域(Cross-Origin)是一个常见的问题,它指的是浏览器的同源策略限制了JavaScript从一个源(协议+域名+端口)访问另一个源的数据。这是一项安全措施,防止恶意脚本窃取或者篡改数据。然而,在某些...

    解决Vue请求接口出现跨域问题.docx

    在本例中,我们将探讨如何解决Vue.js应用在请求接口时遇到的跨域问题。 首先,了解跨域的含义至关重要。跨域是指由于浏览器的同源策略,JavaScript只能向与当前页面同源(即协议、域名和端口完全相同)的服务器发送...

    解决arcgis server跨域问题

    解决arcgis server跨域问题: 1、停掉ArcGIS Server的服务。 2、 打开&lt;ArcGIS Server&gt; \framework\runtime\tomcat\conf\web.xml,注册跨域bean 3、lib下拷贝 cors-filter-2.5.jar java-property-utils-1.9.1.jar包 4...

    Geoserver解决Tomcat跨域问题文件.rar

    在Web开发中,跨域问题是一个常见的安全问题,它源于浏览器的同源策略,限制了JavaScript从一个源(域名、协议或端口)向另一个源发送请求的能力。当用户尝试通过一个源访问由不同源提供的资源时,就会遇到跨域问题...

    完美解决iframe跨域问题

    本文将深入探讨如何“完美解决iframe跨域问题”,并介绍其底层的`window.name`转换代理实现。 **一、iframe跨域的基本概念** 1. **什么是iframe**:iframe是一种HTML元素,允许在单个网页中嵌入另一个网页。它通过...

    MVC+WebAPI跨域调用.rar

    在IT领域,Web应用程序开发经常会遇到跨域问题,特别是在客户端(如浏览器)使用JavaScript与服务端API进行交互时。这个“MVC+WebAPI跨域调用.rar”压缩包文件提供了一个简单的示例,用于演示如何使用jQuery在MVC...

    layer弹窗:top.layer弹窗到父页面跨域解决办法

    标题和描述所提及的是一个关于如何解决layer弹窗在跨域环境下的问题,主要涉及到iframe、跨域以及layer的使用技巧。下面我们将详细探讨这个问题及其解决方案。 首先,我们了解下**iframe**。iframe(Inline Frame)...

Global site tag (gtag.js) - Google Analytics