美文网首页
跨域问题解决方案

跨域问题解决方案

作者: Jerome_Jiang | 来源:发表于2019-01-15 23:45 被阅读9次

什么是跨域?

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

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 ,登陆并进行网银(https://www.baidu.com)操作,这时cookie啥的都生成并存放在浏览器 用户突然想起件事,并迷迷糊糊(https://www.baidu.com)地访问了一个邪恶的网站 www.xiee.com 这时该网站就可以在它的页面中,拿到银行的cookie,比如用户名,登陆token等,然后发起对www.mybank.com 的操作。 如果这时浏览器不予限制,并且银行也没有做响应的安全处理的话,那么用户的信息有可能就这么泄露了。

跨域问题普遍吗?

在现在前后端分离,微服务化之后,往往我们就存在许多不同的域名,这种情况下,就存在非常普遍的跨域问题。因此,跨域问题,在日常开发过程中,是一个非常熟悉的名词。那么,我们是如何去解决跨域问题呢?

解决方案:

方案1:JSONP(不推荐使用)

JSONP是通过在script标签中访问不同域的URL实现跨域:仅限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

        $.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;
    }
    /**
     *
方案二,CORS

CORS全称cross-origin resource sharing,意为跨站点资源共享,是w3c官方推荐的一种跨域方案。
在支持CORS方案的浏览器中发送AJAX请求,请求地址为目标域的绝对路径时,请求头中会带有一个字段:withCredentials: true,这个字段会让浏览器发送身份信息到服务端,如SSL、cookie等。与此同时,在服务端中设置响应头中的Access-Control-Allow-Origin: *,则可以实现一个跨域请求。
但是,不幸的是,CORS不支持IE8、IE9,如果产品不再考虑兼容IE低版本的话,可以忽略,但是如果产品需要兼容目前国内还存在大量低版本的IE市场(百分之二十多),那么这个需要慎重考虑咯。


image.png
主要用途
  • From a browser script perspective: By allowing cross-domain requests, which are subject to tighter controls on the types of data that is exchanged. Cookies, for instance, are blocked unless specifically requested by the XHR author and allowed by the cross-domain web service. This is done to mitigate the risk of data leaks.
  • From a web service perspective: By utilising the origin URL reported by the browser the target cross-domain web service can determine, based on its origin policy, whether to allow or deny the request.
Ajax请求跨域资源的异常

当出现如下异常时,那么就需要考虑跨域的问题了
例如 localhost:63343 通过Ajax请求http://192.168.10.61:8080服务器资源时就会出现如下异常:

image
CORS 实现思路

CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否

安全说明

CORS is not about providing server-side security. The Origin request header is produced by the browser and the server has no direct means to verify it.

CORS 并不是为了解决服务端安全问题,而是为了解决如何跨域调用资源。至于如何设计出 安全的开放API,却是另一个问题了,这里提下一些思路:

  1. 请求时间有效性(验证timestamp与服务接到请求的时间相差是否在指定范围内,比如5分钟内)
  2. token验证
  3. ip验证
  4. 来源验证
    CORS 几种解决方案
    CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否.

Access-Control-Allow-Origin:指定授权访问的域
Access-Control-Allow-Methods:授权请求的方法(GET, POST, PUT, DELETE,OPTIONS等)

一:简单的自定义CORSFilter / Interceptor
适合设置单一的(或全部)授权访问域,所有配置都是固定的,特简单。也没根据请求的类型做不同的处理

在web.xml 中添加filter

<filter>
    <filter-name>cros</filter-name>
    <filter-class>cn.ifengkou.test.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>cros</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

新增CORSFilter 类

@Component
public class CORSFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Max-Age", "1800");//30 min
        filterChain.doFilter(request, response);
    }
}

Access-Control-Allow-Origin只能配置 或者一个域名*
比如配置了192.168.56.130,那么只有192.168.56.130 能拿到数据,否则全部报403异常

response.addHeader("Access-Control-Allow-Origin", "http://192.168.56.130");

方案三,搭建中间转发层(常用)

跨域问题的核心是什么?不同源访问。转换成同源请求,就不存在这个问题啦。

通过搭建中间层,当然可以是java,也可以是node.js,通过将服务端的请求进行转发,换句话说,就是dispatcher了一层,那么前端请求的地址,就被转发了,所以很好的解决跨域问题。

当然,如果对性能有考量的产品,就需要慎重选择这个方案咯,因为多了一层中间转发,不管是网络开销,还是性能负载都是有一定的影响。

方案四,Nginx反向代理(常用)

通常开发环境可以通过设置proxy解决跨域问题,而生产环境下要么把前端项目放在后端项目里,要么设置cor解决跨域问题,前者不利于前后端分离,后者需要后端配置,而现在使用nginx做启动服务设置反向代理可以很好解决跨域问题。
Nginx的思路,就是通过Nginx解析URL地址的时候进行判断,将请求转发的具体的服务器上。

server {
        listen       9000;
        server_name  localhost;

        location / {
            root   H:/app/dist;
            index  index.html;
        }
        #设置代理转发
        location /api/ {
          proxy_pass   http://localhost:9600/;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

通过上面的设置,在重启服务,可以让页面中所有包含 /api/ 字段的请求都转为由服务器去向http://localhost:9600/地址发送请求,从而巧妙的解决了浏览器的跨域问题。

总结

开发环境可以用CORS的方式解决跨域,实现上相对简单,在生产环境尽量使用Nginx代理方式更安全,主推Nginx反向代理方案。

相关文章

  • 跨域问题,解决方案

    跨域问题,解决方案 - Nginx反向代理跨域问题,解决方案 - CORS方案此为原作者的链接:跨域问题,解决之道

  • Web前后端跨域问题处理

    跨域问题有前台跨域(iframe间)和后台跨域。 前台跨域的解决方案可以采用跨域文档通讯(Cross domain...

  • 开发环境跨域和生产环境跨域

    开发环境跨域 前后端分离,IP地址不同,请求数据必然导致跨域问题;解决方案:proxy设置 生产环境跨域 解决方案...

  • Js请求跨域问题

    一、请求跨域问题概述 跨域:指的是协议名、端口或者域名不一致的情况都是跨域。 二、跨域问题的解决方案 1、同域代理...

  • 2、JS-Web-API知识点

    跨域问题:跨域的解决方案?教程: https://www.imooc.com/video/6238https://...

  • Spring Boot使用CORS解决跨域问题

    一、跨域问题描述 Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等。CORS 与 ...

  • JWT简记

    JSON Web Token(JWT)是目前最流行的跨域认证解决方案。 跨域认证问题及传统解决方案 传统认证流程 ...

  • uni-app之浏览器跨域问题解决方案

    Chrome调试跨域问题解决方案 1.跨域CORS(Cross-Origin Resource Sharing) ...

  • 跨域

    博客 说说跨域那些事儿 不要再问我跨域的问题了 前端常见跨域解决方案(全) 同源策略 JSONP(填充式JSON)...

  • 面试官:那有没遇到跨域问题,如何解决跨域?

    面试官:有没遇到跨域问题,如何解决跨域? 一、同源策略 谈到跨域问题,要先谈浏览器的同源策略。 二、解决方案 1、...

网友评论

      本文标题:跨域问题解决方案

      本文链接:https://www.haomeiwen.com/subject/ggtpdqtx.html