lpn520 发表于 2013-1-29 11:45:10

基于JAVA的ajax代理的研究实现

前言
随着web2.0的发展,ajax变的越来越流行,并且已经深入到了许多web应用中。web2.0带来的还不仅仅是技术上和用户体验上的革新,更重要的是他使互联网的信息更为开放,内容提供商们把私有的数据和服务通过web service(SOAP,REST)的方式暴露给他们的用户,用户可以遵循一定限制的基础上的对这些数据进行重新编排并展示。


ajax跨域问题描述
当数据位于同一个域内的时候ajax可以很容易的获取数据,如图一所示。但是很多人在尝试使用ajax去获取位于不同域的数据(例如yahoo的web service)会遇到了ajax不能跨域访问的问题,如图二所示。

http://p.blog.csdn.net/images/p_blog_csdn_net/jamesxu326/EntryImages/20081211/proxy1.gif
图一 在同一个域中ajax获取服务器端数据没有问题

http://p.blog.csdn.net/images/p_blog_csdn_net/jamesxu326/EntryImages/20081211/proxy2.gif

图二 ajax无法跨域获取位于yahoo域内的数据

    其实并不是ajax无法实现跨域访问,而是出于安全性的考虑,一般的浏览器都禁止了这个危险的操作。其实在新兴的RIA应用框架中,诸如adobe的air就可以通过ajax进行跨域访问(当然必须在air的sandbox限制之下)。

 
 
AJAX跨域问题的解决方法解决方案一: 编写ajax web代理程
Ajax web代理即是在服务器端写一个代理程序将客户端请求重新打包再发送到目标服务器获取数据,如图三所示:

http://p.blog.csdn.net/images/p_blog_csdn_net/jamesxu326/EntryImages/20081211/proxy3.gif
图三 ajax代理原理图

http://p.blog.csdn.net/images/p_blog_csdn_net/jamesxu326/EntryImages/20081211/11111.jpg
图四 ajax路由四种http请求原理图

名词解释:
    客户端:ajax请求的发起端。
    客户端请求方式:主要有GET,POST,PUT,DELETE四种基本HTTP请求方式
    请求参数:对于GET,PUT,DELETE请求,请求参数直接以query字段的形式写在URL里,POST的请求参数写在请求的body体中
    Ajax代理: ajax代理必须在ajax可以访问的域中。
    目标服务器:AJAX真实想访问的网址所在的服务器。
    目标服务器响应编码:即被请求的目标服务器响应时的编码方式。

应用场景:
用户需要在自己的应用中使用yahoo的news rss service,根据不同的查询,订阅新闻。
yahoo rss webservice的目标地址为http://news.search.yahoo.com/news/rss
查询参数为
p=查询参数,如“奥运”
ei=结果编码,如“GBK”
fl=0
x=wrt
 
 
 
 
使用ajax代理后的请求步骤:
(1)客户端请求AJAX代理
     客户端请求Ajax代理时,需要给出请求的目标地址和请求参数。
     对于get,put,delete方式的请求,请求参数是可以直接附着在url上的,示例代码如下,这里queryPath如果含有中文参数的话需要用encodeURIComponent重新编码两次(至于为什么我也不太清楚,大家可以查看相关资料),否则ajax代理无法正确读取中文参数,出现乱码。

<li style="padding: 0px; margin: 25px;">//构造查询连接字符串 var targetUrl = "http://news.search.yahoo.com/news/rss"<li style="padding: 0px; margin: 25px;">var queryPath = "p=奥运&ei=GBK&fl=0&x=wrt"; var url = "http://localhost/ajaxproxy?proxyReqUrl="+targetUrl<li style="padding: 0px; margin: 25px;">//打开连接 xmlHttp.open("post", url, true);<li style="padding: 0px; margin: 25px;">//设置回调函数 xmlHttp.onreadystatechange = updatePage;<li style="padding: 0px; margin: 25px;">//设置服务器响应请求体参数 xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded;");  <li style="padding: 0px; margin: 25px;">//发送请求 xmlHttp.send(queryPath); 
 
其中http://localhost/ajaxproxy为ajax代理,proxyReqUrl为客户端请求的目标地址。

 
 
 
(2)Ajax代理请求目标服务器
     ajax代理(通常是一个servlet)程序获取客户端请求的目标地址proxyReqUrl,请求参数,以及客户端的请求方式(GET,POST,PUT,DELETE),并根据客户端请求方式将请求路由到目标服务器(有一些ajax代理不根据用户的请求方式,统一采用GET或者POST的方式提交用户请求,这样做会因为目标服务器无法接受这种请求获取不到数据,例如REST应用就是根据不同的请求方式来决定做什么操作返回什么样的数据的,因此请求方式决定了restful webservice的行为方式)。
以下程序是一个典型的ajax代理实现:

package ajax.proxy.web; import java.io.IOException; import java.io.PrintWriter;import java.net.URLDecoder; import java.net.URLEncoder;import java.util.Enumeration; import java.util.HashMap;import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException;import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod;import org.apache.commons.httpclient.params.HttpMethodParams; import ajax.proxy.*; public class AjaxProxyServlet extends HttpServlet {      /**       * Processes requests for both HTTP <code>GET</code> and <code>POST</code> and <code>PUT</code> and <code>DELETE</code> methods.            * @param request servlet request   * @param response servlet response            */protected void processRequest(HttpServletRequest request, HttpServletResponse response)         throws ServletException, IOException {//请求参数               Map<String,String> params = new HashMap<String,String>();//客户端请求方式               String method = request.getMethod();//目标服务器响应的编码               String encoding = "UTF-8";//目标服务器地址               String url = null;//获取参数键值名称                Enumeration<String> enu = request.getParameterNames();while (enu.hasMoreElements()) {// 取得参数名称列表                        String paramName=(String)enu.nextElement();// 处理本请求参数以及发送给第三方服务器的参数                        if(paramName.equals("ajaxReqUrl")){try {                            // 获取目标服务器地址,并对目标服务器中的中文进行重新编码url=ProxyUtils.rebuildURL(URLDecoder.decode(request.getParameter(paramName),"utf-8"), "gbk");                         } catch (Exception e) {e.printStackTrace();                         }   }else{                            String aParamValue = request.getParameter(paramName);   params.put(paramName, aParamValue);                        }}                   //取得ajax代理AjaxProxy proxy = ProxyFactory.getProxyInstance(method,url,params,encoding);               //获取ajax代理响应AjaxResponse resp = proxy.getAjaxResponse();               //输出必须用UTF-8编码response.setCharacterEncoding("UTF-8");               PrintWriter out = response.getWriter();System.out.println(url);               out.println(resp.getContent());      }            /**      * Handles the HTTP <code>GET</code> method.               * @param request servlet request      * @param response servlet response               */      protected void doGet(HttpServletRequest request, HttpServletResponse response)       throws ServletException, IOException {      processRequest(request, response);               }       /**       * Handles the HTTP <code>POST</code> method.            * @param request servlet request   * @param response servlet response            */   protected void doPost(HttpServletRequest request, HttpServletResponse response)   throws ServletException, IOException {         processRequest(request, response);            }          protected void doDelete(HttpServletRequest request, HttpServletResponse response)   throws ServletException, IOException {                  processRequest(request, response);   }                   protected void doPut(HttpServletRequest request, HttpServletResponse response)   throws ServletException, IOException {         processRequest(request, response);            }   /**       * Returns a short description of the servlet.         */   public String getServletInfo() {   return "Short description";   } }  
 
程序开始时候先获得用户请求方式method, 请求目标地址url,请求参数params,再根据目标地址的响应编码(一般都预先得知),通过这四个参数从proxyFactory中获取合适的proxy,并调用getAjaxResponse方法来获得目标地址响应。
 
<li style="margin-top: 25px; margin-right: 25px; margin-bottom: 25px; margin-left: 25px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">//取得ajax代理 AjaxProxy proxy = ProxyFactory.getProxyInstance(method,url,params,encoding);<li style="margin-top: 25px; margin-right: 25px; margin-bottom: 25px; margin-left: 25px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">//获取ajax代理响应 AjaxResponse resp = proxy.getAjaxResponse(); 
页: [1]
查看完整版本: 基于JAVA的ajax代理的研究实现