JQ之$.ajax()方法以及ajax跨域请求

AJAX(Asynchronous javascript AND xml :异步javascript和xml):是一种创建交互式网页应用的网页开发技术。AJAX可以在不重新加载整个页面的情况下与服务器进行交互。

AJAX的应用范围:

  登录失败不跳转页面

  注册时验证用户是否存在

  图片服务器进行延时加载

  多页数据进行翻页

  自动制新页面等。

AJAX的写法:

 $.ajax({
url:"请求地址",
type:"请求方式",
data:"请求数据",
dataType:"服务器响应的数据类型",
success:function(msg){
//请求成功要做的事,msg:服务器响应的数据
},请求成功后的回调函数
error:function(XMLHttpRequest,textStatus,errorThrown){ } 请求失败或者超时的回调函数
})

  这里是一个最简单的ajax请求,其中包括的参数还有很多,见下表:

参数 值/描述
url 发送请求的地址,一般为string类型
type 请求的方式,值一般为:get/post
async 设置请求为异步还是同步请求,值:true(默认):异步请求、false:同步请求
data 需要向服务器发送的请求数据,值要以key/value的格式,如{name:"123",pwss:"123"}如果请求方式为get,会将数据连接到url上
datatype 服务器返回过来的数据类型是以什么格式返回的,值:xml、html、script、json、jsonp,text
timeout 设置本地请求超时时间,单位:毫秒。此设置将覆盖$.ajaxSetup()方法的全局设置。
cache 表示浏览器是否缓存请求的页面,默认值为true
beforeSend 请求发送前要执行的函数。要求为Function类型的参数
complete 请求完成后要执行的函数。在success和error执行完后执行。参数也为Function
success 请求成功后所执行的回调函数。第一个参数为:服务器响应的dataType类型的数据,第二个参数是描述状态的字符串,第三个为XMLHttpRequest对象
error 请求失败后所执行的回调函数。第一个参数为XMLHttpRequest对象,第二个为描述状态的字符,每三个为error异常
contentType 发送数据到服务器时所使用的内容类型。默认是:"application/x-www-form-urlencoded"。
dataFilter 用于处理 XMLHttpRequest 原始响应数据的函数。
username 要求为String类型的参数,用于响应HTTP访问认证请求的用户名。
password 要求为String类型的参数,用于响应HTTP访问认证请求的密码。
global 表示是否触发全局ajax事件。设置为false将不会触发全局ajax事件,ajaxStart或ajaxStop可用于控制各种ajax事件。
ifModified 仅在服务器数据改变时获取新数据。服务器数据改变判断的依据是Last-Modified头信息。默认值是false。
jsonp 在一个jsonp请求中重写回调函数的名字。该值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分,例如{jsonp:'onJsonPLoad'}会导致将"onJsonPLoad=?"传给服务器。
processData 默认为true,发送的数据将被转换为对象(从技术角度来讲并非字符串)以配合默认内容类型"application/x-www-form-urlencoded"。如果要发送DOM树信息或者其他不希望转换的信息,请设置为false。
scriptCharset 只有当请求时dataType为"jsonp"或者"script",并且type是GET时才会用于强制修改字符集(charset)。通常在本地和远程的内容编码不同时使用。

  

AJAX跨域请求

  //注:转载自https://blog.csdn.net/csdn_ds/article/details/73691134

  以上的方法对于AJAX来说只能在同下个域名下进行请求访问,如果我们需要跨域请求要怎么做呢?

  如果AJAX出现跨域请求,浏览器就会报:XMLHttpRequest cannot load http://目标地址No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://当前页面地址' is therefore not allowed access. 错误

  为什么会出现跨域问题

    跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。

    在此说明一下,所谓的同源,指的是域名、协议、端口均相等。举例如下:

    http://www.abc.com/a/b 调用 http://www.abc.com/d/c(非跨域)

    http://www.abc.com/a/b 调用 http://www.def.com/d/c (跨域:域名不一致)

    http://www.abc.com:81/a/b 调用 http://www.abc.com:82/d/c (跨域:端口不一致)

    http://www.abc.com/a/b 调用 https://www.abc.com/d/c (跨域:协议不同)

    请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

  解决跨域问题有以下三种方法:

    1、使用jsonp

    2、服务器代理

    3、在服务端设置response header中Access-Control-Allow-Origin字段。

  1、使用jsonp

    jsonp解决跨域问题的原理是,浏览器的script标签是不受同源策略限制的,我们可以在script标签中访问任何域名下的资源文件。利用这一特性,用script标签从服务器中请求数据,同时服务器返回一个带有方法和数据的js代码,请求完成,调用本地的js方法,来完成数据的处理。

前端实现,以Jquery的ajax方法为例:

 $.ajax({
url:"",
dataType:'jsonp',
data:'',
jsonp:'callback', //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback) success:function(result) {
//成功的处理
},
error:function(){
//错误处理
}
});

服务端此时返回的不能是普通的json字符串,而是一段可以被前端js执行的一段js代码。

比较一下json与jsonp格式的区别:

json格式:

 {
"message":"获取成功",
"state":"1",
"result":{"name":"工作组1","id":1,"description":"11"}
}

jsonp格式:

 callback({
"message":"获取成功",
"state":"1",
"result":{"name":"工作组1","id":1,"description":"11"}
})

从格式来看,jsonp是在json的基础上包装了一个方法名,此方法名是前端请求传过来的,如请求地址为:http://localhost:9999/tookApp/tbk/getItem?callback=JSONP_CALLBACK,那么方法名就是JSONP_CALLBACK。

下面提供一段java代码,对象转jsonp的工具类:

 package com.tooklili.app.web.util;

 import javax.servlet.http.HttpServletRequest;

 import org.apache.commons.lang.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import com.fasterxml.jackson.databind.util.JSONPObject; /**
*
* @author ding.shuai
* @date 2016年8月15日上午9:47:02
*/
public class AppUtil { /**
* 判断json字符串是否需要转化成jsonp格式
* @param request
* @param result
* @return
*/
public static Object conversionJsonp(Object result){
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
return conversionJsonp(request, result);
} public static Object conversionJsonp(HttpServletRequest request,Object result){
String callback = request.getParameter("callback");
if(StringUtils.isNotEmpty(callback)){
return new JSONPObject(callback, result);
}
return result;
}
}

jsonp的缺点:

1、JSONP是一种非官方的方法,而且这种方法只支持GET方法,不如POST方法安全。(从实现机制就可明白)。

2、JSONP的实现需要服务器配合,如果是访问的是第三方的服务器,我们没有修改服务器的权限,那么这种方式是不可行的。

2、服务器代理

这种方式运用的就是服务器的反向代理技术,控制客户端和服务器的访问都从代理服务器经过,比如用nginx作为服务器代理,在nginx上配置客户端和第三方服务的反向代理,这样就可保证客户端、第三方是同源的了,同一个源,都来自代理服务器。

关于nginx的反向代理配置,可访问我的这篇博客:http://blog.csdn.net/csdn_ds/article/details/58605591

服务器代理的缺点:

开发比较麻烦,对开发环境比较严格,需要在本机上配置代理服务器。

优点:

完美解决使用jsonp,第三方服务没有修改权限的问题。程序的代码侵入性小,代码级别不需要考虑跨域问题。

3、在服务端设置response header中Access-Control-Allow-Origin字段

在被请求的Response Header中加入如下代码:

如果所有请求都想让其他域名的服务通过浏览器ajax请求到,可以通过Filter统一设置response header。

 package com.tooklili.app.web.filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse; /**
* 设置公共属性的过滤器
* @author shuai.ding
*
* @date 2017年6月21日上午11:02:27
*/
public class CommonSetFilter implements Filter{ @Override
public void init(FilterConfig filterConfig) throws ServletException {
} @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//解决跨域问题
HttpServletResponse httpServletResponse =(HttpServletResponse)response;
// 指定允许其他域名访问
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
// 响应类型
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST");
// 响应头设置
httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type"); chain.doFilter(request, response);
} @Override
public void destroy() {
} }

此处说明一下,笔者亲测:只设置Access-Control-Allow-Origin属性也是可以的。

Access-Control-Allow-Origin:* 表示允许任何域名跨域访问

如果需要指定某域名才允许跨域访问,只需把Access-Control-Allow-Origin:*改为Access-Control-Allow-Origin:允许的域名

例如:response.setHeader(“Access-Control-Allow-Origin”,”http://www.client.com”);

缺点:

1、此种解决跨域方案,需要浏览器支持H5,因为这是HTML5解决跨域的方式,如果产品面向的是PC端,这种方式可能就不是一个好的解决方案,如果面向的是手机端,此方法不为一个简单、粗暴的好方式。

2、设置*,存在安全隐患。

4、总结

综上三种解决跨域的方案,个人感觉使用服务代理最好,没有破坏浏览器的安全策略,但这个对开发环境要高一点。设置response header的方式,根据具体情况分析,要考虑清楚产品面向的用户。对于jsonp这种方式,虽然没有破坏浏览器的安全策略,但只支持get方式的请求,有点不能接受,因为get传输有参数长度的限制,同时又要考虑传输中文的乱码问题,但如果项目中只是简单的查询、展示,这种方式还是可以考虑的。

其他好文推荐

Access-Control-Allow-Origin 跨域设置多域名:http://www.jianshu.com/p/b587dd1b7086

上一篇:GCC 命令行详解 -L 指定库的路径 -l 指定需连接的库名(转载)


下一篇:【Hibernate 3】一对一映射配置