浏览器的跨域问题

跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域,并有以下注意事项:

1、表单默认提交(跳转页面或刷新页面)、超链接访问域外的资源,这是允许的,因为在点击按钮/超链接时,浏览器地址已经变了,这就是一个普通的请求,不属于跨域

2、ajax(借助xmlhttprequest)跨域请求,这是被禁止的,因为ajax就是为了接受接受响应,这违背了,不允许跨域读的原则;

3、jsonp属于跨域读且形式限制为GET方式,它利用了script标签的特性;这是允许的。因为浏览器把跨域读脚本,当作例外,类似的img、iframe的src都可以请求域外资源

4、出现Access control allow origin错误,说明是跨域请求失败!浏览器发送请求成功,同时浏览器也接收到响应了,但是限制了XmlHttpRquest接收请求,不会让xmlhttprequest接受到响应,并且在js控制台报错。这也就是我们在网络控制台(Network)能看见http 状态码是200,但是在js控制台(Console)出现js错误的原因。

跨域访问的几种方式
1. 通过jsonp方式进行跨域(仅限get请求):
(1)前端jquery的jsonp方式;
(2)前端AngularJS的jsonp方式;
(3)手动实现jsonp;

jsonp方式进行跨域访问的原理:

其本质是利用了标签具有可跨域的特性,由服务端返回预先定义好的javascript函数的调用,并且将服务端数据以该函数参数的形式传递过来。

JSONP技术和Ajax没有关系。

我们知道<script>标签可以加载跨域的javascript脚本,并且被加载的脚本和当前文档属于同一个域。

因此在文档中可以调用/访问脚本中的数据和函数。

如果javascript脚本中的数据是动态生成的,那么只要在文档中动态创建<script>标签就可以实现和服务端的数据交互。

JSONP就是利用<script>标签的跨域能力实现跨域数据的访问,请求动态生成的JavaScript脚本同时带一个callback函数名作为参数。

其中callback函数本地文档的JavaScript函数,服务器端动态生成的脚本会产生数据,并在代码中以产生的数据为参数调用callback函数。当这段脚本加载到本地文档时,callback函数就被调用。

代码如下:

(1)前端jquery的jsonp方式:

  function crossDomainJsonp() {
        $.ajax({
            type:"get", 
            url:"http://192.168.2.23/pdf/crossDomeJsonp1.do",
            async:true,
            data:{},
            dataType: "jsonp",  //返回类型为jsonp,实现跨域
            jsonp:"callback",   //jsonp和jsonpCallBack相当于在url后添加一个参数:?callback=back
            jsonpCallback:"back",   //设定回调函数的名字,传到后台,进行包装,不设定自动生成
            success: function(data) {   //成功执行处理,对应后台返回的back(data)方法
                alert(data);
                console.log(data);
            }
        });
    }

后台代码:

/**
     * 
    * @Title: crossDomeJsonp1
    * @Description: TODO(jsonp方式一)
    * @return MappingJacksonValue    返回类型
    * @param callback
    * @return
     */
    @RequestMapping(value="crossDomainJsonp1", method=RequestMethod.GET)
    @ResponseBody
    public MappingJacksonValue crossDomainJsonp1(String callback) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            resultMap.put("success", true);
        } catch (IllegalStateException e) {
            e.printStackTrace();
            resultMap.put("success", false);
        }
        //包装jsonp
        MappingJacksonValue jacksonValue = new MappingJacksonValue(resultMap);
        //设置包装的回调方法名
        jacksonValue.setJsonpFunction(callback);

        return jacksonValue;
    }


    /**
     * 
    * @Title: crossDomeJsonp2
    * @Description: TODO(jsonp方式二)
    * @return String    返回类型
    * @param callback
    * @return
     */
    @RequestMapping(value="crossDomainJsonp2", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8")
    @ResponseBody
    public String crossDomainJsonp2(String callback) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            resultMap.put("success", true);
        } catch (IllegalStateException e) {
            e.printStackTrace();
            resultMap.put("success", false);
        }
        //把对象转换成json数据(自定义的JSONUtils)
        String jsonResult = JSONUtils.objectToJson(resultMap);
        //拼接字符串
        String resultStr = callback + "(" + jsonResult + ");";

        return resultStr;
    }

(2)前端AngularJS的jsonp方式:AngularJS的$http 也提供了对jsonp的访问,直接调用jsonp进行跨域访问

$http.jsonp('http://192.168.2.23/pdf/crossDomeJsonp1.do?callback=back')
        .success(function(data) {
            alert(data);
            console.log(data);
        }).error(function(err) {
            alert('error:' + err);
        });

后台同上

(3)手动实现jsonp
jsonp的本质而都是通过加载javascript的方式来做的,所以如果项目没有依赖jQuery或者AngularJS,则可以自己手动实现jsonp的调用。

原理很简单,就是用javascript动态加载一个script文件,同时定义一个callback函数给script执行而已。

 //定义callback 函数
    function back1(data) {
        alert(data);
        console.log(data);
    }
    //通过添加script标签,进而执行js(执行完成应该删除生成的script)
    function crossDomain2() {
        //创建并加载script
        var script = document.createElement('script');
        script.src = 'http://192.168.2.23/pdf/crossDomeJsonp1.do?callback=back1';
        document.body.appendChild(script);
    }

2. 服务器端设置请求头Access-Control-Allow-Origin实现跨域

传统的跨域请求没有好的解决方案,无非就是jsonp和iframe,随着跨域请求的应用越来越多,W3C提供了跨域请求的标准方案(Cross-Origin Resource Sharing)。
IE8、Firefox 3.5 及其以后的版本、Chrome浏览器、Safari 4 等已经实现了 Cross-Origin Resource Sharing 规范,实现了跨域请求。
在服务器响应客户端的时候,带上Access-Control-Allow-Origin头信息。
• 如果设置 Access-Control-Allow-Origin:*,则允许所有域名的脚本访问该资源。
• Access-Control-Allow-Origin:http://www.phpddt.com.com,允许特定的域名访问。

前端:正常的ajax请求
后台:

/**
     * 
    * @Title: crossDome1
    * @Description: TODO(通过设置响应头Access-Control-Allow-Origin解决跨域请求)
    * @return Map<String,Object>    返回类型
    * @param response
    * @return
     */
    @RequestMapping(value="crossDomain1", method=RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> crossDomain1(HttpServletResponse response) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            //利用Access-Control-Allow-Origin响应头解决跨域请求
//          response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8020");
            resultMap.put("success", true);
        } catch (IllegalStateException e) {
            e.printStackTrace();
            resultMap.put("success", false);
        }
        return resultMap;
    }

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值