当前访客身份:游客 [ 登录  | 注册加入尚学堂]
启用新域名sxt.cn
新闻资讯

使用Web代理实现Ajax跨域

我来了! 发表于 2年前  | 评论(0 )| 阅读次数(774 )|   0 人收藏此文章,   我要收藏

目前的工作项目分为前端和后 台,双方事先约定接口,之后独立开发。后台每天开发完后在测试服务器上部署,前端连接测试服务器进行数据交互。前端和后台分开的好处是代码不用混在一个工 程里一起build,互不干涉。但由此也引发出一个问题,那就是Ajax跨域。目前的项目是一个Single Page App, 基本上所有数据交互都是通过Ajax请求来完成的。为了方便平时前端开发,必须解决跨域问题。

跨域方案有多种,我认为基本上可分为两大类,一类是需要目标Server配合的,另一类则不需要。前者限制稍多,必须由服务器显式允许跨域才行,比 如返回HTTP头信息,修改服务器配置,返回JavaScript等。可以用JSONP,iframe等方式实现。后者主动权就掌握在跨域客户端,服务器 不用为此做任何配置。这就是本文要说的Web代理。

作为前端开发,自然希望主动权在自己手里,不用劳烦Sever配合。所以我选择了使用Web代理方案。该方案的原理其实很简单,就是将跨域请求转变 为同源请求。具体来说,就是在本地搭建一个Web站点(代理),该站点可以向目标服务器发送HTTP请求,接收响应。它的行为跟浏览器类似,因此目标服务 器是不用区分对待的。然后将本地的前端站点也部署到这个Web站点中,这样它们就属于同一个域了。所有针对目标服务器的Ajax请求,都发送到这个代理, 然后由代理负责转发和接收响应。这样就避开了跨域之名,却有跨域之实。

setting

图有点丑,欢迎拍砖。

剩下的就是实现细节了。由于对Asp.Net比较熟悉,就用它创建一个Web站点。在实现过程中,我觉得有几点细节需要关注一下。

HTTP Request拦截

由于事先不知道会有哪些请求(就算知道,请求的URL可能也会太多),不可能针对每个URL写一个转发规则。因此需要获取所有Ajax请求,经过统 一的处理再转发到目标服务器。众所周知,Asp.Net的IHttpHandler接口定义了针对某个具体的HTTP请求的处理方法,如前所述,不可能为 每个请求URL写一个Handler,有没有一种办法可以获取任何请求的信息?答案是HttpModule。HttpModule是先于 HttpHandler处理的,所以在这里可以做些手脚。定义一个HttpModule也很简单,只要实现IHttpModule接口,监听 Request事件就可以了。当然,需要在Web.config文件里注册这个HttpModule才能使用。

XDomainProxy.cs定义:

public class XDomainProxy : IHttpModule
{ public void Dispose() { } public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(Application_BeginRequest);
        context.EndRequest += new EventHandler(Application_EndRequest);
    } public void Application_BeginRequest(object sender, EventArgs e)
    {

    } public void Application_EndRequest(object sender, EventArgs e)
    {
        HttpApplication application = sender as HttpApplication;
        HttpContext context = application.Context;
        HttpResponse response = context.Response;
        response.StatusCode = 200;
    }
}



在Web.config中注册HttpModule:

<configuration>
	<system.web>
		<httpHandlers> ... </httpHandlers>
	    <httpModules>
	      <add name="ProxyModule" type="AAProxy.Proxy"/>
	    </httpModules>
	</system.web>
</configuration>



模拟HTTP请求

.Net 已经封装好了HttpWebRequest和HttpWebResponse两个关键的类,非常方便。

//实例化web访问类
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
request.Method = context.Request.HttpMethod;
request.ContentType = context.Request.ContentType;

string postData = context.Request.Form.ToString();
byte[] postdatabytes = Encoding.UTF8.GetBytes(postData);
request.ContentLength = postdatabytes.Length;
request.AllowAutoRedirect = false;
request.CookieContainer = loginCookie;
request.KeepAlive = true;
request.UserAgent = context.Request.UserAgent; if (context.Request.HttpMethod == "POST")
{
    Stream stream; stream = request.GetRequestStream();
    stream.Write(postdatabytes, 0, postdatabytes.Length);
    stream.Close();
}

//接收响应 response = (HttpWebResponse)request.GetResponse();
 using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
{
    string content = reader.ReadToEnd();
}



这样就完成了一个简单的HTTP请求。注意POST请求需要另外发参数。

Cookie

由于所有的Ajax请求都需要用户登录才能进行,所以代理程序也必须模拟用户登录目标服务器站点。用户的登录信息是保存在cookie里的,所以在模拟请求的时候还需要保存cookie。HttpWebRequest有个CookieContainer属性,就是用来装cookie的。保存好cookie后,之后的每个请求都必须带上它,这样才能维持登录状态。另外,还需要把这些cookie写到浏览器中。这里需要注意,.Net封装了两个关于cookie的类,HttpCookie和Cookie。前者是Asp.Net程序写回给浏览器用的,而后者是向别的服务器发起HTTP请求时用的。所以代理程序收到目标Server返回的Cookie对象时,要转换成HttpCookie对象再返回给浏览器。

//response是目标服务器的响应对象,context是返回给浏览器的上下文对象
void SetCookie(HttpWebResponse response, HttpContext context)
{
    foreach (Cookie cookie in response.Cookies)
    {
        HttpCookie httpCookie = new HttpCookie(cookie.Name, cookie.Value);
        httpCookie.Domain = cookie.Domain;
        httpCookie.Expires = cookie.Expires;
        httpCookie.Path = cookie.Path;
        httpCookie.HttpOnly = cookie.HttpOnly;
        httpCookie.Secure = cookie.Secure;
        context.Response.SetCookie(httpCookie);
    }
}



Https连接

在使用过程中发现,如果目标服务器的数字证书是不受信任的,连接将被拒绝。这在连接Server端开发同事的PC调试时不方便,怎么破?.Net对Http请求有个证书验证机制,只要让这个验证总是通过就好了。(一切为了开发方便)

ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidateRemoteCertificate); private bool ValidateRemoteCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{ return true;
}



部署Web代理

部署就很简单了,新建一个IIS站点,根目录指向前端项目的路径,设定一个端口号。将Web代理发布到本地的某个目录下,然后作为一个应用程序添加到之前的IIS站点中即可。

总结

经过以上几个关键步骤,基本上搭建好了Web代理。当然,这个过程中还有一些细节需要关注,比如转发请求的URL映射处理,Session过期,异常处理等。总的来说,没有用到什么高深的技术,只是针对各种跨域方案做了一个选择。

原文:使用Web代理实现Ajax跨域

分享到:0
关注微信,跟着我们扩展技术视野。每天推送IT新技术文章,每周聚焦一门新技术。微信二维码如下:
微信公众账号:尚学堂(微信号:bjsxt-java)
声明:博客文章版权属于原创作者,受法律保护。如果侵犯了您的权利,请联系管理员,我们将及时删除!
(邮箱:webmaster#sxt.cn(#换为@))
北京总部地址:北京市海淀区西三旗桥东建材城西路85号神州科技园B座三层尚学堂 咨询电话:400-009-1906 010-56233821
Copyright 2007-2015 北京尚学堂科技有限公司 京ICP备13018289号-1 京公网安备11010802015183