使用Web代理实现Ajax跨域
目前的工作项目分为前端和后台,双方事先约定接口,之后独立开发。后台每天开发完后在测试服务器上部署,前端连接测试服务器进行数据交互。前端和后台分开的好处是代码不用混在一个工程里一起build,互不干涉。但由此也引发出一个问题,那就是Ajax跨域。目前的项目是一个Single Page App, 基本上所有数据交互都是通过Ajax请求来完成的。为了方便平时前端开发,必须解决跨域问题。
跨域方案有多种,我认为基本上可分为两大类,一类是需要目标Server配合的,另一类则不需要。前者限制稍多,必须由服务器显式允许跨域才行,比如返回HTTP头信息,修改服务器配置,返回JavaScript等。可以用JSONP,iframe等方式实现。后者主动权就掌握在跨域客户端,服务器不用为此做任何配置。这就是本文要说的Web代理。
作为前端开发,自然希望主动权在自己手里,不用劳烦Sever配合。所以我选择了使用Web代理方案。该方案的原理其实很简单,就是将跨域请求转变为同源请求。具体来说,就是在本地搭建一个Web站点(代理),该站点可以向目标服务器发送HTTP请求,接收响应。它的行为跟浏览器类似,因此目标服务器是不用区分对待的。然后将本地的前端站点也部署到这个Web站点中,这样它们就属于同一个域了。所有针对目标服务器的Ajax请求,都发送到这个代理,然后由代理负责转发和接收响应。这样就避开了跨域之名,却有跨域之实。

图有点丑,欢迎拍砖。
剩下的就是实现细节了。由于对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跨域的更多相关文章
- asp.net web api2.0 ajax跨域解决方案
asp.net web api2.0 ajax跨域解决方案 Web Api的优缺点就不说了,直接说怎么跨域,我搜了一下,主要是有两种. 一,ASP.NET Web API支持JSONP,分两种 1, ...
- 浅谈linux 下,利用Nginx服务器代理实现ajax跨域请求。
ajax跨域请求对于前端开发者几乎在任何一个项目中都会用到,众所周知,跨域请求有三种方式: jsonp; XHR2 代理: jsonp: 这种应该是开发中是使用的最多的,最常见的跨域请求方法,其实aj ...
- 用iframe设置代理解决ajax跨域请求问题
面对ajax跨域请求的问题,想用代理的方式来解决这个跨域问题.在服务器端创建一个静态的代理页面,在客户端用iframe调用这个代理 今天在项目中需要做远程数据加载并渲染页面,直到开发阶段才意识到aja ...
- 支持Ajax跨域访问ASP.NET Web Api 2(Cors)的简单示例教程演示
随着深入使用ASP.NET Web Api,我们可能会在项目中考虑将前端的业务分得更细.比如前端项目使用Angularjs的框架来做UI,而数据则由另一个Web Api 的网站项目来支撑.注意,这里是 ...
- web api 跨域请求,ajax跨域调用webapi
1.跨域问题仅仅发生在Javascript发起AJAX调用,或者Silverlight发起服务调用时,其根本原因是因为浏览器对于这两种请求,所给予的权限是较低的,通常只允许调用本域中的资源,除非目标服 ...
- Web Api 2(Cors)Ajax跨域访问
支持Ajax跨域访问ASP.NET Web Api 2(Cors)的简单示例教程演示 随着深入使用ASP.NET Web Api,我们可能会在项目中考虑将前端的业务分得更细.比如前端项目使用Ang ...
- $.ajax 跨域请求 Web Api
WepApi确实方便好用,没有配置文件,一个apicontroller直接可以干活了.但今天用$.ajax跨域请求的时候总是获取不到数据,用fiddler一看确实抓到了数据,但回到$.ajax函数中, ...
- AJAX跨域解决方案
从AJAX诞生那天起,XMLHttprequest对象不能跨域请求的问题就一直存在,这似乎是一个很经典的问题了,是由于javascript的同源策略所导致. 解决的办法,大概有如下几种: 1. 使用中 ...
- 浅析Ajax跨域原理及JQuery中的实现分析
AJAX 的出现使得网页可以通过在后台与服务器进行少量数据交换,实现网页的局部刷新.但是出于安全的考虑,ajax不允许跨域通信.如果尝试从不同的域请求数据,就会出现错误.如果能控制数据驻留的远程服务器 ...
随机推荐
- 随笔001:Group by 语法剪辑
基本语法: GROUP BY [ALL] group_by_expression[,……n][WITH (CUBE|ROLLUP)] 参数说明: ALL:用于指定包含所有组和结果集,甚至包含那些其中任 ...
- 深入理解JavaScript中的this关键字
1. 一般用处 2. this.x 与 apply().call() 3. 无意义(诡异)的this用处 4. 事件监听函数中的this 5. 总结 在JavaScript中this变量是一个令人难以 ...
- 类的访问修饰符_C#
访问控制修饰符: 访问控制修饰符 类内部 子类 程序集内 程序集外 Default √ Public √ √ √ √ Private √ Internal √ √ √ Protected √ √ Pr ...
- CSS的浮动和清除
CSS浮动和清除 什么是浮动? 在实现效果上,让元素浮起来(飘起来),动起来(向左或向右移动) 浮动本质:就是将两个块元素同存一行. float 取值:主要是对浮动的方向进行控制 left:让元素向左 ...
- 关于内存的5个函数(malloc,VirtualAlloc,GlobalAlloc,LocalAlloc,HeapAlloc)
VirtualAlloc 该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0 一次分配 1PAGE 以上的 R ...
- 一种C# TCP异步编程中遇到的问题
最近在维护公司的一个socket服务端工具,该工具主要是提供两个socket server服务,对两端连接的程序进行数据的透明转发. 程序运行期间,遇到一个问题,程序的一端是GPRS设备,众所周知,G ...
- J2EE中文乱码处理
在JAVA WEB开发的过程中,经常会遇到中文乱码的情况,中文乱码主要是在浏览器与服务器交互传递数据的时候发生的.对于这个棘手的问题,我参考(韩顺平老师)视频将处理方法总结与此,供自己以及大家开发的时 ...
- ajax中的post方法中回调函数不执行的问题
前一段时间接触了JQuery Ajax中的.post()方法和.get()方法,感觉到ajax的简洁和强大,当用到.post()方法时,去W3上查找相关的使用方法,感觉十分简单,用法很明了,然后,直接 ...
- 【Java Web】Eclipse中配置Marven环境
1 Marven简介 Apache Maven,是一个软件(特别是Java软件)项目管理及自动构建工具,由Apache软件基金会所提供.基于项目对象模型(缩写:POM)概念,Maven利用一个中央信 ...
- Python的文件与文件夹操作
Python的文件与文件夹操作 Python OS模块 1.重命名:os.rename(old, new) 2.删除:os.remove(file) 3.列出目录下的文件 :os.listdir(pa ...