sunmaobin.github.io icon indicating copy to clipboard operation
sunmaobin.github.io copied to clipboard

跨域解决方案推荐

Open sunmaobin opened this issue 7 years ago • 0 comments

背景

跨域问题对于前端来说,是一个老生常谈的问题了,无论是平时工作中,以及面试中基本都会问到。本文将梳理常见的几种跨域的优缺点,以及建议的跨域解决方案。

基础

什么是跨域?跨域有哪些解决方案?等等基础知识,请参考这篇文章,讲的比较细致,这里就不在啰嗦。

https://segmentfault.com/a/1190000011145364

对比

我们在工作中,用的比较多的三种解决方案:

方案 优点 缺点 适用场合
JSONP 1、使用简单;
2、不需要任何配置;
1、GET请求;
2、数据不安全,任何人都可以调用接口;
3、存在XSS攻击
1、安全系数要求低;
2、临时使用的接口;
3、应急接口解决方案;
CORS 1、相对安全,但是如果后台配置 Access-Control-Allow-Origin = * 就不那么安全了;
2、后台或者Nginx需要配置,如果需要携带Cookie,则前端Ajax也需要配置参数;
1、需要配置跨域的相关参数,比较麻烦;
2、如果跨域的 Origin 配置为 * , 不安全
1、运行环境可以自主灵活配置;
2、跨域只能代码层面处理理;
PROXY代理 1、非常安全,同域请求;
2、前后端代码不需要任何配置
1、对运行环境要求较高,需要配置代理;
2、开发时也需要配置代理才能连调接口
1、运行环境可以自主灵活配置;
2、安全系数要求比较高;

PROXY 代理,就是通过代理软件或者Nginx将地址进行转发,以达到请求接口的地址在同一个域的目的。

JSONP

最主要的缺点就是 不安全,所以公司里面建议不要使用!

CORS

CORS,在公司里面用的比较多,对于CORS的服务端配置,一般有以下两种方式:

  1. 在后台代码里统一拦截处理reponseHeader,设置CORS协议头;
  2. 在Nginx配置中,统一拦截返回response,设置CORS协议头;

这两种方案,第一种不需要依赖外部环境,纯粹在代码层面就可以解决问题。对于第二种方案,就比较依赖外部环境。那么,一般这两种方案如何选择呢?我个人给如下建议:

  • 推荐 如果代码层面分层合理,建议直接在代码层面设置拦截器,统一拦截处理CORS。这么做的好处就是,一套代码无论以后部署在哪里都可以,不需要对外部环境提太多要求,自身系统健壮性比较强。另外,在代码层面处理CORS还有个好处,就是在开发连调、测试阶段,也依然可以方便进行。不然如果太依赖外部环境的话,开发连调环节,也需要搭建一套环境做为中间转发,比较麻烦。
  • 不推荐 当然,也有人在Nginx中配置CORS,这么做的话,对代码的要求就降低了,不需要考虑跨域问题,但就是多了一个中间环节,无论在开发、测试还是线上,都需要这个中间层,这一点不是很方便。所以,如果是用CORS,不建议使用Nginx配置。

实际项目中,使用CORS典型的场景:H5代码部署在CDN,而后台部署在某后台服务器上。

这种场景下,典型的CDN的环境很难自由配置,而又必须依赖后台接口数据,这时候最好的 办法就是后台代码开发时,就支持跨域。

PROXY代理

PROXY代理 的方法就是通过代理层做一次中间的转发,使得对于浏览器来说,就不存在跨域的问题。

这种方式最大的好处就是绝对安全,不会由于跨域引来一些安全风险,但是缺点就是中间需要做一层代理转发。

实际项目中,使用PROXY代理典型的场景:给客户或者用户使用的后台系统,原因主要在于:

  • 对外的一些后台系统,对于安全性和稳定性要求较高;
  • 同时,管理后台对于Cookie等状态依赖比较强;
  • 后台的一些特殊组件,比如上传组件,有时候对于跨域是比较敏感,所以最好是不跨域,一劳永逸;

如果采用这种方式,那在开发和测试阶段,分别怎么做呢?

本地开发连调

本地 + MockServer

前端代码不需任何配置,只需要MockServer配置 CORS 支持跨域请求就可以。

本地 + 他人机器Server

本地需要安装代理软件,如:Charles

假设,上线后真实的访问路径和接口为:

  • 前端页面地址:http://abcd.vivo.com.cn
  • 后台接口地址:http://abcd.vivo.com.cn/api

假设,本地和他人机器Server真实的服务地址为:

  • 前端页面服务:http://localhost:8080 (本地的Node服务)
  • 后台接口地址:http://172.25.122.86:8888 (他人的Tomcat后台服务)

这时候需要配置 Charles 路由 Map Remote规则:

Imgur

注意:后台接口的路由规则一定要放在前面,即:/api/* 的路由放在页面。

配置好上面的代理后,地址栏直接访问:http://abcd.vivo.com.cn 即可。

生产环境Nginx配置

我们在本地是通过代理软件转发,而测试或者生产环境,则直接通过Nginx的规则,就可以将上述的路由规则做转发,达到同样的目的。

配置 nginx.conf 文件:

server {
    listen  80;
    server_name abcd.vivo.com.cn;
    
    location / {
        proxy_pass  http://172.25.122.85:3000;
    }
    
    location ~ /api/ {
        proxy_pass  http://172.25.122.86:8080;
    }
}

上述配置可以理解为:

  • 监听80端口,将 http://abcd.vivo.com.cn 的所有请求服务转发到 172.25.122.85:3000
  • http://abcd.vivo.com.cn/api/ 或者 http://abcd.vivo.com.cn/api/list 等请求转发到http://172.25.122.86:8080

总结

本文主要对比了3种常见的解决跨域的方案,同时重点介绍了 CORSPROXY代理的一些优缺点,以及最适合的场景,归纳总结一下,就是:

  • JSONP,能不用就不用,完全不推荐;
  • CORS,最适合用于部署在CDN上面的项目,比如:H5项目;
  • PROXY代理,最合适管理后台,比如:对外的给客户或者用的管理系统;

(全文完)

sunmaobin avatar May 02 '18 12:05 sunmaobin