#! https://zhuanlan.zhihu.com/p/402874502
我们前端开发人员,在开发中,经常会遇到跨域问题。
跨域问题实际上是浏览器自个加的限制,主要目的就是为了保障用户信息的安全,详见浏览器的同源策略
例如,前端页面在本地起在8080
端口,起的后端部署在本地3000
端口,8080
发送 xhr 到 3000
,结果就因为跨域策略挂了。
这时候我们通常会使用 2 种方式来帮我们解决:
一种 服务端设置 CORS
策略来帮我们解决 (下文不涉及 jsonp
)
CORS 全称 Cross-Origin Resource Sharing,跨域资源共享
它由众多的请求头组成,详见 MDN
另一种 就是在开发时候,使用正向代理 (proxy) , 来帮助我们解决跨域问题。
这 2 种方式都是服务端的解决方案。
值得一提的是, Chrome 新的默认
Referrer-Policy : strict-origin-when-cross-origin
, 在请求的credentials mode
是include
(XMLHttpRequest.withCredentials
) 的情况下,Access-Control-Allow-Origin: *
默认是禁止的,必须显式声明
刚刚也说过浏览器的同源策略,是自己给自己的一个限制,
所以我们可以在服务端自定义 http 请求,来绕过这一层限制,这就是使用正向代理的本质。
以前端最熟悉的 webpack-dev-server
配置为例:
// webpack.config.js
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' }
},
'/baidu': {
target: 'https://www.baidu.com',
changeOrigin: true
}
}
}
}
原理实际上非常简单,同源请求在 webpack-dev-server
的 http-proxy-middleware
中转化成服务端 http 请求,代理到目标域名那去罢了。
一图以蔽之:
假如我们要把,本地的 webpack-dev-server
的 proxy
效果,直接部署到公网上,该怎么办呢?
最快的方式,就是,依靠 serverless framework
, 直接把整个站 (包括前后端),部署到腾讯 SCF 平台,来作为我们线上网站的代理
主要有 2 种做法:
一种以使用 网站和 SCF 不同域名的方式来部署
另一种使用 网站和 SCF 相同域名的方式来部署
下面简称 多域名模式
, 和 单域名模式
废话不多说,直接上图
这里我们把网站的静态资源,上传到 COS
上,再同步到 CDN
。
这样我们的网站实际部署在 CDN
上,给 CDN
配置域名之后,我们也只需要设置我们 SCF
绑定的 API网关
的 cors
策略,把我们的域名加进去就可以。
这样用户从 CDN
获取页面和静态资源后,再向 SCF
绑定的API网关
域名发送跨站请求,以此达到代理的目的。
单域名模式就有些不同点了,还是看图
这里我们把网站的,除了作为入口的index.html
, 其他的静态资源都上传到 COS
上,再同步到 CDN
那。
SCF 当然可以去返回静态资源,就是有点浪费算力。
这里我们把 index.html
放入了 SCF
内部,这样用户直接访问 API网关
的地址,就可以通过 static
中间件 + history fallback
(router history mode) , 把页面返回给前端。
这里的 CDN
需要配置 CORS
策略,把 API网关
所绑定的自定义域名,设置进 CDN
->高级配置
中的 HTTP响应头配置
规则里。
在图上可以看到,用户在访问 SCF
中的页面,以及向SCF
发送请求的时候,都是走的同源的请求。
可以看到,这 2 种模式都各有优劣,
CDN
还是必不可少的,毕竟不同网络节点多,速度快,可以有效减少用户等待时间。CORS
策略,只不过多域名模式,CORS 策略需要在 API 网关,或者SCF
内部代码中设置,单域名模式 , 其他静态资源的 CORS
策略 需要在CDN
那里配置。这篇文章最终写下来,实际上是探讨的在 Serverless 架构中,如何部署前端的方式。
假如我们使用的是服务端渲染 (SSR),可以看做成 单域名模式
的一种衍生,CDN
作为动静分离的一种方式,内部动态的部分,还是放在SCF
内部,交给它做渲染。
component: scf
name: sit-history-proxy
inputs:
src:
src: ./
exclude:
- .env
- node_modules/**
- yarn.lock
type: web
name: ${name}-function
region: ap-shanghai
runtime: Nodejs12.16
installDependency: true
entryFile: src/app.js
eip: true
environment:
variables:
NODE_ENV: production
events:
- apigw:
parameters:
protocols:
- http
- https
environment: release
endpoints:
- path: /
method: ANY