js跨域请求服务与用serlet代理跨域请求

1、jquery直接请求服务器数据

很多开发人员在使用jquery在前端和服务器端进行数据交互,所以很容易会认为在前端利用jquery就可以读取任何站点的数据了。近日在进行开 发时,因为要在本地测试与另一台服务器进行数据交互。然后 正好就遇到了浏览器端跨域访问的问题。

跨域的安全限制都是指浏览器端来说的,服务器端不存在跨域安全限制的问题。

目前浏览器端跨域访问常用的两种方法有两种:

1、通过jQuery的ajax进行跨域,这其实是采用的jsonp的方式来实现的。

jsonp是英文json with padding的缩写。它允许在服务器端生成script tags至返回至客户端,也就是动态生成javascript标签,通过javascript callback的形式实现数据读取。

html页面端示例代码:

jQuery(document).ready(function(){
        $.ajax({
            type : "get", //jquey是不支持post方式跨域的
            async:false,
            url : "http://api.taobao.com/apitools/ajax_props.do", //跨域请求的URL
            dataType : "jsonp",
            //传递给请求处理程序,用以获得jsonp回调函数名的参数名(默认为:callback)
            jsonp: "jsoncallback",
            //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
            jsonpCallback:"success_jsonpCallback",
            //成功获取跨域服务器上的json数据后,会动态执行这个callback函数
            success : function(json){
                alert(json);
            }
        });
    });

服务器端示例代码,以java为例:

服务器端代码,是重点,开始以为,只要客户端通过jsonp就可以直接跨域访问,其实不然,需要服务器端的支持才行。

public void jsonpTest() throws IOException{
    HttpServletRequest request = ServletActionContext.getRequest();
    HttpServletResponse response = ServletActionContext.getResponse();
    //根据html指定的jsonp回调函数的参数名,获取回调函数的名称
    //callbackName的值其实就是:success_jsonpCallback
    String callbackName = (String)request.getAttribute("jsoncallback");
    //简单模拟一个json字符串,实际可使用google的gson进行转换,次数通过字符串拼接
    //{"name":"张三","age":28}
    //\是对"号进行转义
    String jsonStr = "{\"name\":\"张三\",\"age\":28}";
    //最终返回的数据为:success_jsonpCallback({"name":"张三","age":28})
    String renderStr = callbackName+"("+jsonStr+")";
    response.setContentType("text/plain;charset=UTF-8");
    response.getWriter().write(renderStr);
}

jsonp的原理:

首先在客户端注册一个callback (如:'jsoncallback'), 然后把callback的名字(如:success_jsonpCallback)传给服务器端对应的处理函数。

服务器先生成需要返回给客户端的 json 数据。然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数(jsoncallback)的值(success_jsonpCallback) 。

最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端(重点)
客户端浏览器,解析script标签,并将服务器端返回的数据,作为参数,
传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里。

实际上跨域是通过动态增加script来加载数据,无法直接获得数据,所以需要使用回调函数。

2、通过代理servlet去请求数据,然后返回前端

通过上网查找资料,发现直接通过js去请求数据存在安全隐患,所以有另外一种解决方法就是通过js请求自己的服务代理ProxyServlet

原理,通过url请求,传递参数,以输入输出流的方式去获取数据,后台主要代码如下:

@Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/plain; charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        ltype = request.getParameter("ltype");
        StringBuffer buffer = new StringBuffer();
        /*
         * 拼接参数
         * */
        buffer.append("fg=").append(fg+"&").append("ltype=").append(ltype+"&")
        .append("channelid=").append(channelid+"&").append("imei=").append(imei+"&")
        .append("vi=").append(vi);
        String result = post(url, buffer.toString());
        JSONObject jb = JSONObject.fromObject(result);
        out.print(jb.toString());
        out.flush();   
        out.close();  
    }
public static String post(String url, String params)
    {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuffer result = new StringBuffer();
        try
        {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
//            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            conn.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
//            conn.setRequestProperty("Accept","*/*");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(params);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));
            String line = "";
            while ((line = in.readLine()) != null)
            {
                result.append(line);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                    out = null;
                }
                if (in != null)
                {
                    in.close();
                    in = null;
                }
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
        }
        return result.toString();
    }

如此,后台返回给前台的是json字符串,前台解析就OK了,前台解析代码如下

//普通
                $.ajax({
                    type    :    'post',
                    url        :    '../ProxyServlet',
                    data    :    {
                        'ltype'    :    'nor'
                    },
                    dataType:    'json',
                    success    :    function(json){
                        var $results = json.results;
                        var ul = document.getElementById("rec");
                        $($results).each(function(i){
                            //当前app对象
                            var obj = this;
                            //动态生成一个Li
                            var li = document.createElement("li");
                            //动态生成一个img
                            var img = document.createElement("img");
                            //动态生成一个a
                            var a = document.createElement("a");

                            img.src = obj.icon;
                            a.href = obj.downurl;
                            a.innerHTML = obj.title;
                            //组装li
                            li.appendChild(img);
                            li.appendChild(a);
                            ul.appendChild(li);
                        });
                    }
                });

因为后台返回前台是已经处理好的json值,所以,前台就直接用了,不用再解析

 

我这里前台动态创建节点的时候,不知道为什么用jquery失效了,所以这里用的是原生js创建的

posted @ 2013-08-12 11:46  离尘  阅读(372)  评论(0)    收藏  举报