一种方便的跨域开发解决方案

catalog: 前端

现在越来越多的 Web 项目都采取前后端分离的开发方式,也就是在开发过程中前端工程运行在一个 node server 上,同时提供 REST API 的后端工程作为独立的服务运行在另一个 server 上,这样前后端通过 HTTP 请求进行通信的时候就会遇到跨域的问题,跨域是怎么一回事大家应该都了解,这里就不再赘述。以往解决跨域问题比较常用的方法就是给服务端配置 CORS,但是这种方式会带来一些不便:

要修改后端代码,如果后端项目运行在自己机器上还好,如果是运行在别的服务器上,甚至是其他团队在维护,那么修改一段代码就会比较麻烦,并且还要确保这些代码不会被发布到生产环境中去。

每次启动浏览器的时候要输入一长串代码来关闭浏览器的安全策略,比如 Chrome 浏览器的命令如下: 不仅麻烦,万一一不小心在这种模式下访问了一些敏感的数据,还会带来安全隐患。

开发模式下前端调接口要带上测试后端服务器的 URL,因此发布到生产环境之前还要把它去掉。

总之就是比较麻烦,体会不到那种脱了裤子就上,完事提上裤子就走的爽快感,我说的是上厕所。所以今天就是要介绍一种更加简单安全的解决方案,同时我们会深入去了解其中的原理是什么。

首先,用 create-react-app 创建一个前端项目,假如你的前端项目运行的地址是 ,与此同时提供 API 的后端项目运行的地址是 ,你要做的只是在前端工程的 package.json 文件中添加这样一行配置:

然后你就会神奇地发现,从前端页面发出的 HTTP 请求,虽然访问的依然是 3000 端口,但是会被自动转发到 4000 端口的后端服务器并得到正确的响应,于此同时访问页面的请求却不会被转发,依然能够被前端路由捕获,这样我们就完全不需要再考虑如何处理跨域的问题了。问题是解决了,但是又出现了 2 个问题萦绕在我的心中:

package.json 中的 参数是作用在什么地方的?

是怎么样做到把访问页面的请求和访问 REST API 的请求区分开的?

带着这样的疑问我们一起去看看create-react-app的源码是怎样写的,首先在前端项目中的 package.json 里我们能看到,项目启动执行的脚本是 ,所以我们打开文件 create-react-app/packages/react-scripts/scripts/start.js(为何直接能定位到这个文件,以及 react-script 这个命令是如何注册的,属于其他知识点,本文不展开说明,有疑问的童鞋可以去这里 学习一个),我们看到有以下代码:

此处的 的声明在 create-react-app/packages/react-scripts/config/paths.js 中:

因此我们就知道,这里的 就是我们之前在前端工程的 package.json 中定义的 的值,然后我们看到, 被用来生成了 ,最终 作为配置参数创建了 实例。webpack-dev-server 是一个用于启动 webpack 的测试服务器,并且提供了诸如 HMR 等方便开发的功能,因此我们就得出第一个结论:前端工程的 package.json 中定义的 值,是作用于 WebpackDevServer,最终通过 WebpackDevServer 进行的转发

让我们继续试图解答第二个问题——是怎么样做到把访问页面的请求和访问 REST API 的请求区分开的?我们看到 首先是被传入 方法得到 ,然后在 方法中返回了一个对象,并且对象的 字段的值为 ,最终该对象就是 webpack-dev-server 的配置项,在 webpack-dev-server 文档 中可以看到 proxy 的作用就是做一层代理,把从页面来的请求转发到另一个地址,因此关键就在于 的配置是怎么样的,于是目光转移到 方法, 方法的定义在 create-react-app/packages/react-dev-utils/WebpackDevServerUtils.js 中,在这里我们可以看到首先是对 进行了类型和格式的检测,然后如果 是一个格式正确的字符串,就返回一个只有一个对象元素的数组,在这个对象中的 字段中出现了如下的判断:

在这里我们看到有对 进行判断, 用于表示浏览器通过这次 HTTP 请求希望获取到的内容类型,因此如果 accept 中带有 则说明本次请求获取的是一个 document,因此就不应该被转发到后端,这一堆判断逻辑用一幅图表示出来如下:

在这里 context 的含义在 webpack-dev-server 文档中是找不到的,它的说明出现在http-proxy-middleware中,context 支持传入一个 function 用于自定义转发的逻辑,只在返回值为 true 时才转发请求,因此该代理将只会转发 ajax 或者 fetch 发出的 HTTP 请求 。

除了文中提到的这种最简单的配置,webpack-dev-server 的 proxy 还支持多种配置方式以同时满足多种代理规则,感兴趣的同学可以去文档里面了解更多细节。

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180320G1LH5800?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券