ajax前台后台跨域请求处理方式


Posted in Javascript onFebruary 08, 2018

最近一直在搞公众号前台开发,遇到了ajax跨域请求的问题,像地区的省-市-县三级联动、汽车品牌-车系-车款的三级联动查询等都需要调用外部接口(其他工程项目的接口)完成。下面就分享一下个人解决跨域请求的方案,当然是在后台程序猿大哥的帮助下,我才弄明白了其中的渊源,赶紧记录下来慢慢积累,也希望对大家能有所帮助,还请积极提出意见或建议。

跨域请求需要借助后台代码接收callback回调函数,对json数据进行进一步处理;前台再用ajax请求向服务器发送callback参数,并指定数据格式为jsonp。

一、后台对跨域请求进行处理

1.CarBrandController.java(汽车品牌接口java文件),这里列出的方法主要用来根据不同的level值查询对应的品牌、车系、车款,在这里对跨域请求做一个接收回调函数的处理,如果返回的callback为null,则不是跨域请求,不需要做特殊处理,直接打印json接口数据即可;如果返回的callback不为null,则表示跨域请求,这时要对json数据做一个特殊处理,即在json数据的外层加一对小括号包起来,具体请看HttpAdapter.java文件中的printlnJSONObject方法。

public void json(HttpServletRequest request,HttpServletResponse response){ 
  Map<String,Object>map=new HashMap<String, Object>(); 
  String id = request.getParameter("id");      //接收ajax请求带过来的id 
  String level = request.getParameter("level");   //接收ajax请求带过来的level 
  String callback=request.getParameter("callback"); //接收ajax请求带过来的callback参数 
  if ("1".equals(level)) {             //如果level是'1',则查询第一级目录内容 
    map.put("results", this.carBrandService.findByAttr(null, "first_letter asc")); //调用查询方法,结果放入map 
  } else if ("2".equals(level)) {          //如果level是'2',则查询第二级目录内容 
    map.put("results", this.carSerieService.findByAttr("parent_id="+id, "first_letter asc"));//调用查询方法,结果放入map 
  } else if ("3".equals(level)) {          //如果level是'3',则查询第三极目录内容 
    map.put("results", this.carModelYearService.findByAttr("parent_id="+id, "jian_pin desc"));//调用查询方法,结果放入map 
  } 
  map.put("level",level); 
  if (null==callback) {               //如果接收的callback值为null,则是不跨域的请求,输出json对象 
    HttpAdapter.printlnObject(response, map); 
  }else{                      //如果接收的callback值不为null,则是跨域请求,输出跨域的json对象 
  HttpAdapter.printlnJSONPObject(response, map, callback); 
  } 
}

2.HttpAdapter.java(输出对象的java文件),printlnObject方法打印正常json字符串;printlnJSONObject方法对json字符串进行了特殊处理。

/** 
 * 打印对象 
 * @param response 
 * @param object 
*/ 
public static void printlnObject(HttpServletResponse response,Object object){ 
  PrintWriter writer=getWriter(response); 
  writer.println(JSON.toJSONString(object)); 
} 
/** 
 * 打印跨域对象 
 * @param response 
 * @param object 
*/ 
public static void printlnJSONPObject(HttpServletResponse response,Object object,String callback){ 
  PrintWriter writer=getWriter(response); 
  writer.println(callback+"("+JSON.toJSONString(object)+")"); 
}

二、前台ajax跨域请求数据

写法1:向服务器发送一个参数callback=?,同时指定dataType为'jsonp'的格式,跨域请求时指定的数据格式必须是jsonp的形式。

function loadData(obj,level,id,value){ 
  $.ajax({  
    url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id+'&callback=?',   //将callback写在请求url后面作为参数携带 
    type:'GET', 
    async:false, 
    dataType:'jsonp', 
    success:function(data){         
      console.log(data);             
      //其他处理(动态添加数据元素)       
  });    
}

写法2:callback不需要写在url中,但是要指定jsonp参数为'callback',并给jsonpCallback参数一个值。

function loadData(obj,level,id,value){ 
  $.ajax({  
    url:'http://192.168.1.106:8086/carBrand/json.html?level='+level+'&id='+id, 
    type:'GET', 
    dataType:'jsonp', 
    jsonp: 'callback',          //将callback写在jsonp里作为参数连同请求一起发送 
    jsonpCallback:'jsonpCallback1',    
    success:function(data){            
    console.log(data);       
}); }

以上两种写法的含义是一样的,只是写法不同罢了。

接下来补充一下jsonp的工作原理。

三、jsonp跨域的原理解析

jsonp的最基本的原理是:动态添加一个<script>标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了.

JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。如果要进行跨域请求,我们可以通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递javascript对象。这种跨域的通讯方式称为JSONP。

jsonCallback 函数jsonp1236827957501(....): 是浏览器客户端注册的,获取跨域服务器上的json数据后,回调的函数

Jsonp原理:

首先在客户端注册一个callback (如:'jsoncallback'), 然后把callback的名字(如:jsonp1236827957501)传给服务器。注意:服务端得到callback的数值后,要用jsonp1236827957501(......)把将要输出的json内容包括起来,此时,服务器生成 json 数据才能被客户端正确接收。

然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 'jsoncallback'的值 jsonp1236827957501 .

最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。

客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时javascript文档数据,作为参数,
传入到了客户端预先定义好的 callback 函数(如上例中jquery $.ajax()方法封装的的success: function (json))里.(动态执行回调函数)

可以说jsonp的方式原理上和<script src="http://跨域/...xx.js"></script>是一致的(qq空间就是大量采用这种方式来实现跨域数据交换的) .JSONP是一种脚本注入(Script Injection)行为,所以也有一定的安全隐患.

注意,jquey是不支持post方式跨域的.

Javascript 相关文章推荐
对象特征检测法判断浏览器对javascript对象的支持
Jul 25 Javascript
在JS中最常看到切最容易迷惑的语法(转)
Oct 29 Javascript
写JQuery插件的基本知识
Nov 25 Javascript
javascript实现五星评价代码(源码下载)
Aug 11 Javascript
JavaScript实现带箭头标识的多级下拉菜单效果
Aug 27 Javascript
jQuery.Callbacks()回调函数队列用法详解
Jun 14 Javascript
总结javascript中的六种迭代器
Aug 16 Javascript
jQuery实现磁力图片跟随效果完整示例
Sep 16 Javascript
jQuery zTree树插件简单使用教程
Jan 10 Javascript
Javascript DOM事件操作小结(监听鼠标点击、释放,悬停、离开等)
Jan 20 Javascript
jQuery Datatables表头不对齐的解决办法
Nov 27 jQuery
微信小程序实现列表的横向滑动方式
Jul 15 Javascript
详解自定义ajax支持跨域组件封装
Feb 08 #Javascript
微信小程序实现验证码获取倒计时效果
Feb 08 #Javascript
ES6 迭代器(Iterator)和 for.of循环使用方法学习(总结)
Feb 08 #Javascript
详解 vue better-scroll滚动插件排坑
Feb 08 #Javascript
VUE + UEditor 单图片跨域上传功能的实现方法
Feb 08 #Javascript
关于vue中watch检测到不到对象属性的变化的解决方法
Feb 08 #Javascript
使用veloticy-ui生成文字动画效果
Feb 08 #Javascript
You might like
Terran历史背景
2020/03/14 星际争霸
谈谈关于php的优点与缺点
2013/04/11 PHP
PHP中file_exists使用中遇到的问题小结
2016/04/05 PHP
PHP使用反射机制实现查找类和方法的所在位置
2016/04/22 PHP
PHP排序算法之直接插入排序(Straight Insertion Sort)实例分析
2018/04/20 PHP
php中的钩子理解及应用实例分析
2019/08/30 PHP
Javascript类定义语法,私有成员、受保护成员、静态成员等介绍
2011/12/08 Javascript
给html超链接设置事件不使用href来完成跳
2014/04/20 Javascript
js+html5绘制图片到canvas的方法
2015/06/05 Javascript
javascript比较两个日期相差天数的方法
2015/07/23 Javascript
javascript:void(0)是什么意思及href=#与href=javascriptvoid(0)的区别
2015/11/13 Javascript
浅析JavaScript回调函数应用
2016/05/22 Javascript
JS获取鼠标位置距浏览器窗口距离的方法示例
2017/04/11 Javascript
Javascript中八种遍历方法的执行速度深度对比
2017/04/25 Javascript
Bootstrap 表单验证formValidation 实现表单动态验证功能
2017/05/17 Javascript
vue 封装自定义组件之tabal列表编辑单元格组件实例代码
2017/09/07 Javascript
原生JS实现的多个彩色小球跟随鼠标移动动画效果示例
2018/02/01 Javascript
js拖动滑块和点击水波纹效果实例代码
2018/10/16 Javascript
详解webpack打包后如何调试的方法步骤
2018/11/07 Javascript
如何为vuex实现带参数的 getter和state.commit
2019/01/04 Javascript
Python使用Selenium+BeautifulSoup爬取淘宝搜索页
2018/02/24 Python
Python socket实现的简单通信功能示例
2018/08/21 Python
python中几种自动微分库解析
2019/08/29 Python
Django 拼接两个queryset 或是两个不可以相加的对象实例
2020/03/28 Python
css3圆角边框和边框阴影示例
2014/05/05 HTML / CSS
美国和加拿大计算机和电子产品购物网站:TigerDirect.com
2019/09/13 全球购物
广州迈达威.net面试题目
2012/03/10 面试题
科室工作的个人自我评价
2013/10/30 职场文书
新任教师自我鉴定
2014/02/24 职场文书
企业总经理任命书
2014/06/05 职场文书
民事赔偿协议书
2014/11/02 职场文书
家长对孩子的寒假评语
2015/10/09 职场文书
2019年“我为祖国点赞”演讲稿(3篇)
2019/09/26 职场文书
Java 关于String字符串原理上的问题
2022/04/07 Java/Android
我去timi了,一起去timi是什么意思?
2022/04/13 杂记
python实现双链表
2022/05/25 Python