标签:javascript ajax跨域 jsonp cors
出于安全方面的考虑,Web浏览器中JavaScript无法访问其他服务器上的资源,这个限制仅在Web浏览器中有效。而跨域就是通过某些手段来绕过这个限制,实现不同服务器之间通信的效果。ajax跨域可以通过jsonp、cros或者服务端代理实现。
jsonp利用<script>标签不受限制访问其他服务器资源的特点,通过<script>的src发送跨域访问的url以及参数。jsonp需要对服务端返回的数据格式做修改,服务端返回的数据应该是一个可执行的JavaScript代码。
如果json数据格式如下
{"sex": "男", "name": "小明", "age": 20}
那么jsonp格式应该如下
callback({"sex": "男", "name": "小明", "age": 20});
其中callback是回调函数,一般由jsonp客户端提供。jQuery提供了jsonp请求,下面用jsonp获取京东的订单列表数据。
$.ajax({
url: ‘http://order.jd.com/lazy/getOrderListCountJson.action‘, // jsonp路径
data: {}, // 参数
//jsonp: ‘callback‘, // 服务端接收回调函数的参数,默认是callback
//jsonpCallback: ‘‘, // 回调函数名称,如果不指定jQuery自动生成
dataType: ‘jsonp‘ // 请求类型
}).done(function(json){
// 请求成功处理
console.dir(json);
}).fail(function(){
// 请求失败处理
});
如图所示,jsonp请求属于script请求。
jsonp结果如下
CORS(Cross-Origin Resource Sharing)定义一种跨域访问的机制,可以让AJAX实现跨域访问。实现此功能非常简单,只需服务器添加响应标头Access-Control-Allow-Origin。目前大部分的PC浏览器和几乎所有的移动浏览器都支持CROS。
浏览器 | CROS支持情况 |
---|---|
IE | 从IE8开始支持,其中IE8/IE9部分支持,IE10/IE11完全支持。 |
Firefox | Firefox 3.5+ 开始支持 |
Chrome | Chrome 3+ 开始支持 |
Opera | Opera 12+ 开始支持 |
Safair | Safair 4+ 开始支持 |
服务端代码
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.alibaba.fastjson.JSON;
@Controller
@RequestMapping("/test")
public class TestController {
/**
* 返回json
*
* @param response
*/
@RequestMapping("/json.do")
public void json(HttpServletResponse response) {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
// 添加响应头,支持跨域ajax请求
response.setHeader("Access-Control-Allow-Origin", "*");
// 构造json
Map<String, Object> json = new HashMap<String, Object>();
json.put("date", new Date());
json.put("name", "小明");
json.put("age", 18);
try {
// 这里用FastJSON生成JSON字符串
response.getWriter().write(JSON.toJSONString(json));
} catch (IOException e) {
e.printStackTrace();
}
}
}
页面代码
$.ajax({
url: ‘http://localhost:8280/logweb/test/json.do‘,
dataType: ‘json‘,
success: function(json){
console.dir(json);
},
error: function(){
}
});
如图所示,从CSDN页面发起ajax跨域请求。
如果服务端没有设置响应头Access-Control-Allow-Origin,浏览器会有如下错误提示。
服务端不受跨域请求的限制,可以在服务端代理ajax请求。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
/**
* ajax请求代理
* 用Apache HttpClient模拟发送请求
* 所有请求都以POST方式提交
*/
@WebServlet("/ajax/proxy/servlet")
public class AjaxProxyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// ajax请求的实际url名称
private final String destUrlParamName = "destUrl";
// 编码
private final String encoding = "utf-8";
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求参数
List<NameValuePair> params = getParameters(request);
// ajax请求的实际url
String destUrl = request.getParameter(destUrlParamName);
HttpPost httppost = new HttpPost(destUrl);
CloseableHttpClient httpclient = HttpClients.createDefault();
UrlEncodedFormEntity formEntity;
try{
// 设置请求参数
formEntity = new UrlEncodedFormEntity(params, encoding);
httppost.setEntity(formEntity);
CloseableHttpResponse httppostResponse = httpclient.execute(httppost);
try{
HttpEntity httpEntity = httppostResponse.getEntity();
InputStream httpis = httpEntity.getContent();
OutputStream os = response.getOutputStream();
int len = 0;
byte[] buffer = new byte[1024];
while((len = httpis.read(buffer)) != -1){
os.write(buffer, 0, len);
}
os.flush();
}finally{
httppostResponse.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取ajax请求参数
* @param request
* @return 返回参数对数组
*/
private List<NameValuePair> getParameters(HttpServletRequest request){
Enumeration<String> paramNames = request.getParameterNames();
List<NameValuePair> params = new ArrayList<NameValuePair>();
while(paramNames.hasMoreElements()){
String name = paramNames.nextElement();
// 判断,如果参数是ajax请求的目标路径,则忽略
if(!destUrlParamName.equals(name)){
params.add(new BasicNameValuePair(name, request.getParameter(name)));
}
}
return params;
}
}
ajax跨域请求代码
/**
* ajax代理请求
* @param options ajax配置参数,请参考$.ajax()的配置
*/
function ajaxProxy(options){
// ajax代理的url
var proxyUrl = ‘http://localhost:8280/logweb/ajax/proxy/servlet‘,
destUrl = options.url;
// 把代理url和实际url替换
options.url = proxyUrl;
if(!options.data){
options.data = {};
}
// 把实际url放到参数destUrl中,传递给服务端发送代理请求
options.data.destUrl = destUrl;
options.type = ‘post‘;
return $.ajax(options);
}
下面用ajax代理请求博客园的分页数据
ajaxProxy({
url: ‘http://www.cnblogs.com/mvc/AggSite/PostList.aspx‘, // 博客园分页url
dataType: ‘html‘, // 数据格式是html
data: {
CategoryId: 808,
CategoryType: "SiteHome",
ItemListActionName: "PostList",
PageIndex: 2,
ParentCategoryId: 0
},
success: function(html){
console.dir(html);
//把html直接输出到页面
$(‘body‘).html(html);
},
error: function(){
console.dir(arguments);
}
});
请求参数如图所示
执行结果如图所示
优点 | 缺点 | |
---|---|---|
jsonp | 不存在兼容性问题,大部分js库都支持jsonp。 | 通过script发送请求,url长度有限制,不能发送超过2048字节的请求。服务端需要提供专门的jsonp接口。 |
cros | Web端和服务端基本上不用做代码修改。 | 不能完全兼容所有浏览器。 |
ajax代理 | 不存在兼容性问题 | 相对于jsonp和cros,性能可能较差。服务端需要提供专门的代理。 |
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:javascript ajax跨域 jsonp cors
原文地址:http://blog.csdn.net/accountwcx/article/details/47754767