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创建的

浙公网安备 33010602011771号