ajax跨域

出于安全方面的考虑,Web浏览器中JavaScript无法访问其他服务器上的资源,这个限制仅在Web浏览器中有效。而跨域就是通过某些手段来绕过这个限制,实现不同服务器之间通信的效果。ajax跨域可以通过jsonp、cros或者服务端代理实现。

jsonp

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

jsonp结果如下

jsonp

cors

CORS(Cross-Origin Resource Sharing)定义一种跨域访问的机制,可以让AJAX实现跨域访问。实现此功能非常简单,只需服务器添加响应标头Access-Control-Allow-Origin。目前大部分的PC浏览器和几乎所有的移动浏览器都支持CROS。

浏览器CROS支持情况
IE从IE8开始支持,其中IE8/IE9部分支持,IE10/IE11完全支持。
FirefoxFirefox 3.5+ 开始支持
ChromeChrome 3+ 开始支持
OperaOpera 12+ 开始支持
SafairSafair 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跨域请求。

cors


cors

如果服务端没有设置响应头Access-Control-Allow-Origin,浏览器会有如下错误提示。

cors error

服务端代理

服务端不受跨域请求的限制,可以在服务端代理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);
    }
});

请求参数如图所示

ajax代理

执行结果如图所示

ajax代理

总结

 优点缺点
jsonp不存在兼容性问题,大部分js库都支持jsonp。通过script发送请求,url长度有限制,不能发送超过2048字节的请求。服务端需要提供专门的jsonp接口。
crosWeb端和服务端基本上不用做代码修改。不能完全兼容所有浏览器。
ajax代理不存在兼容性问题相对于jsonp和cros,性能可能较差。服务端需要提供专门的代理。
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值