首页 » jQuery » 跨域和跨域方式(浏览器)

跨域和跨域方式(浏览器)

原文 http://blog.csdn.net/menghuanzhiming/article/details/78980761

2018-01-06 02:00:18阅读(245)

什么是跨域?
理解跨域首先必须要了解同源策略。
同源策略:是浏览器上为安全性考虑实施的非常重要的安全策略。
何谓同源: URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。
例如:

http://api.example.com/detail.html  不同源 域名不同  
https//www.example.com/detail.html   不同源 协议不同  
http://www.example.com:8080/detail.html    不同源    端口不同  
http://api.example.com:8080/detail.html    不同源    域名、端口不同  
https://api.example.com/detail.html    不同源    协议、域名不同  
https://www.example.com:8080/detail.html    不同源    端口、协议不同  
http://www.example.com/detail/index.html    同源    只是目录不同

同源策略解析:
(1)浏览器的同源策略,限制了来自不同源的”document”或脚本,对当前”document”读取或设置某些属性。 从一个域上加载的脚本不允许访问另外一个域的文档属性。
举个例子:
比如一个恶意网站的页面通过iframe嵌入了银行的登录页面(二者不同源),如果没有同源限制,恶意网页上的javascript脚本就可以在用户登录银行的时候获取用户名和密码。
(2)同源策略是浏览器在接收加载资源之前对其来源进行了检查,然后限制加载;
(3)同源策略使浏览器允许跨域写,而不允许跨域读,写就是上行,发送请求,读就是下行,接受响应;
(4)在浏览器中,<script>、<img>、<iframe>、<link>等标签都可以加载跨域资源,而不受同源限制,但浏览器限制了JavaScript的权限使其不能读、写加载的内容。

跨域是指从一个域名的网页去请求另一个域名的资源。比如从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错误的原因。

为什么浏览器要限制跨域访问呢?

原因就是安全问题:如果一个网页可以随意地访问另外一个网站的资源,那么就有可能在客户完全不知情的情况下出现安全问题。
比如下面的操作就有安全问题:
用户访问www.mybank.com ,登陆并进行网银操作,这时cookie啥的都生成并存放在浏览器
用户突然想起件事,并迷迷糊糊地访问了一个邪恶的网站 www.xiee.com
这时该网站就可以在它的页面中,拿到银行的cookie,比如用户名,登陆token等,然后发起对www.mybank.com 的操作。
如果这时浏览器不予限制,并且银行也没有做响应的安全处理的话,那么用户的信息有可能就这么泄露了。

既然有安全问题,那为什么又要跨域呢?

 有时公司内部有多个不同的子域,比如一个是location.company.com ,而应用是放在app.company.com, 
 这时想从 app.company.com去访问 location.company.com 的资源就属于跨域。

跨域访问的几种方式
1. 通过jsonp方式进行跨域(仅限get请求):
(1)前端jquery的jsonp方式;
(2)前端AngularJS的jsonp方式;
(3)手动实现jsonp;
2. 服务器端设置请求头Access-Control-Allow-Origin实现跨域;

1、通过jsonp方式进行跨域(仅限get请求);
jsonp原理:

其本质是利用了标签具有可跨域的特性,由服务端返回预先定义好的javascript函数的调用,并且将服务端数据以该函数参数的形式传递过来。
JSONP技术实际和Ajax没有关系。
我们知道<script>标签可以加载跨域的javascript脚本,并且被加载的脚本和当前文档属于同一个域。
因此在文档中可以调用/访问脚本中的数据和函数。
如果javascript脚本中的数据是动态生成的,那么只要在文档中动态创建<script>标签就可以实现和服务端的数据交互。
JSONP就是利用<script>标签的跨域能力实现跨域数据的访问,请求动态生成的JavaScript脚本同时带一个callback函数名作为参数。
其中callback函数本地文档的JavaScript函数,服务器端动态生成的脚本会产生数据,并在代码中以产生的数据为参数调用callback函数。当这段脚本加载到本地文档时,callback函数就被调用。

代码如下:

(1)前端jquery的jsonp方式:

///跨域ajax请求,jsonp,页面地址http://127.0.0.1:8020/jsonp/index.html
    function crossDomainJsonp() {
        $.ajax({
            type:"get", 
            url:"http://192.168.2.23/pdf/crossDomainJsonp1.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: crossDomainJsonp1
    * @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: crossDomainJsonp2
    * @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/crossDomainJsonp1.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/crossDomainJsonp1.do?callback=back1';
        document.body.appendChild(script);
    }

后台同上

2、服务器端设置请求头Access-Control-Allow-Origin实现跨域
参考链接:Access control allow origin 简单请求和复杂请求http://blog.csdn.net/wangjun5159/article/details/49096445

传统的跨域请求没有好的解决方案,无非就是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: crossDomain1
    * @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;
    }

最新发布

CentOS专题

关于本站

5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!

小提示

按 Ctrl+D 键,
把本文加入收藏夹