这篇文章的主题是如何带着问题去解决问题,不会解释一些简单的概念。
此文的前提是你对跨域的基本理解是 OK 的。如果你是新手朋友,不要着急,后续我会针对跨域问题进行抽丝剥茧的讲解,欢迎关注~
下一篇文章的部分内容:
- 同源策略
- “源” 到底是什么?
- 什么是同源策略?
- 由来及相关文献。
- 跨域都会影响哪些内容?
- 跨域
- 到底是什么在影响我们的请求?
- 简单请求与非简单请求
- 后端解决方案
- 前端解决方案(JSONP、反向代理、postMessage、ws、iframe)
- 代理
- 什么是代理?
- 正向代理、反向代理 的区别是什么?
前言
作为一个开发者,我相信大家都对带着问题去学习深有体会。
如果你是个新入门的开发者,那么你一定躲不开的问题就是学习 git
,在学习的过程中,一定会发现,数不清的命令要记。
记住第二个忘记第一个,不停的在做 狗熊掰棒子 的事儿。
在你真正开始工作之后发现,之前学习的 git
命令全忘光了。随用随查反而学会了 git
的使用。
😡ps:天赋异禀过目不忘的人走开走开~
那么下面的讲解我将遵循以下逻辑:
- 现状概述、需求分析
- 问题调研
- 解决方案
- 写代码
那么我们开始吧!
背景
现状概述
跨域实现
我目前手头有一个 react 项目,项目的 api 一律是 api.sincenir.com
,那么对于 react
来讲,直接通过 package.json
来解决跨域的问题显然是最优解:
{
...,
'proxy': 'https://api.sincenir.com'
}
接口封装
我这里的接口请求还是使用的 axios
,哈哈这么不 react
的方案,主要的原因是为了多项目统一接口封装。具体细节就不讲了,看看伪代码吧~
const configMap = {
'local': {
...
host: ''
},
'production': {
...
host: 'https://api.sincenir.com'
}
}
const getDevType = () => { ... }
const env = getDevType()
axios.baseUrl = configMap[env].host
需求分析
现状讲完了,接下来我们讲讲需求,明确我们的需求,我们才能定位问题、解决问题。
我们最近来了一个新需求,需要用到上传,我们的文件服务器采用的是 OSS
,这里的 OSS
你可以当作成 七牛 或者自己的服务器,都没有关系。
知道我们有了上传需求,接下来我们就需要明确我们的文件上传都需要做什么。
首先,必不可少的就是 Upload
组件,及对应的上传地址等内容。与自己的服务器上传不同的是,我们还需要在上传前通过接口获取 OSS
的签名、上传地址;还需要在上传成功后告诉我们的服务器。
那么我们的上传过程就是:
- 调用
oss.sincenir.com/oss/signature
取 OSS 的上传签名、上传地址等内容 - 通过第一步接口获取到的内容,调用
Upload
组件上传文件 - 调用
oss.sincenir.com/oss/uploadafter
上传文件信息等内容到自己的服务器
问题
通过上面的需求分析,我们会发现,我们需要干的只有三件事。
- 调用
GET
接口oss.sincenir.com/oss/signature
- 调用
OSS
的文件上传接口 - 调用
POST
接口oss.sincenir.com/oss/uploadafter
通过上面的三件事,具体问题具体分析。
第一件事是最简单的,调用一个非 proxy
域名的简单请求。直接请求就好了。
第二件事是比较简单的,就是非 proxy
域名的复杂请求。第一个问题,多域名跨域怎么解决?
第三件事是比较难的,难的点在于,我们的 OSS
限制了请求的主域名为 sincenir.com
,限制域名又该怎么解决?
问题分析
问题1:多域名跨域如何解决?
react
如果我们采用了其他的跨域解决方案,可能就不会出现该问题。
我们采用的方案是 proxy
做反向代理,解决的跨域问题。
该方案是由 react
的脚手架提供的,理论上我们可以通过配置多 proxy
解决多域名跨域问题的。
但是我们大多数人的 create-react-app
是超过 2.0 版本的。超过 2.0 版本会导致一个问题,就是 package.json
中只能配置 string
类型。因而无法使用该方法。
那么剩下的方法就是通过 http-proxy-middleware
解决该问题。
超过 2.0 版本的
create-react-app
会导致package.json
中只能配置string
类型
PS: 这里具体没有细研究原因,计划在跨域大篇章中进行详细调研。
解决方案:
- 安装
http-proxy-middleware
- 新建
setupProxy.js
在src
目录下 - 配置
setupProxy.js
vue
配置 vue.config.js
文件即可。
问题2:访问的服务器做了域名限制怎么办?
这里我当时的直觉是,我们直接让服务器提供接口,前端上传至服务器,服务器再上传至 OSS
服务器。
当然这个方案需要后端配合,主要的工作量便跑到了后端同学那里。于是,我去找了后端同学讲了该问题。
就在后端同学准备开发接口时,乔哥跟我讲可以配置虚拟域名进行上传接口的请求阿。我当时都懵了。我还跟乔哥抬杠,虚拟域名可以请求的话 OSS
的域名限制还有啥用?这也太不安全了,浏览器内核应该不允许这个方案的。
直到乔哥给我发了一篇:阿里云OSS上传文件本地调试跨域问题解决 。
我都懵了,还真行吗?写这篇文章的肯定是问题解决了,那我就跟着试试吧。
教程就不复制了,很简单的几件事:
- 配置本地的
127.0.0.1
映射到sincenir.com
- 配置运行端口(react、vue有些许区别)
- 重启项目
- 访问
sincenir.com
- 正常上传文件
PS:事实证明,人真的不能凭经验、凭本能做事,万事在没有做过之前,要先调研清楚,再做决定。
这样可以很大程度避免进行无用的工作(沟通成本、后端开发成本)。
实现
既然方案都定了,跟着方案走即可。
多域名跨域
react
安装 http-proxy-middleware
执行安装命令
# --save-dev 的原因是,我们只需要本地启动时,通过反向代理解决跨域
npm install http-proxy-middleware --save-dev
创建 setupProxy.js
文件
在 project/src
目录下创建,setupProxy.js
,这里的 project
指的是你的项目。
为了避免大家出错,这里可以理解为和 pages
、 views
目录平级。
配置 setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = function (app) {
app.use(
'/api',
createProxyMiddleware({
target: 'https://api.sincenir.com',
changeOrigin: true
})
)
app.use(
'/oss',
createProxyMiddleware({
target: 'https://oss.sincenir.com',
changeOrigin: true
})
)
}
需要注意的一点是:
如果项目开启了严格模式,禁止了require
命令,直接使用eslint
的忽略。// eslint-disable-next-line @typescript-eslint/no-var-requires
vue
vue 多域名就更简单了,直接修改 vue.config.js
文件。
module.exports = {
...
devServer: {
proxy: {
"/api": {
target: "http://api.sincenir.com",
changeOrigin: true,
ws: true,
crossorigin: "anonymous",
pathRewrite: {
"^/api": "/api",
},
},
"/oss": {
target: "https://oss.sincenir.com",
changeOrigin: true,
ws: true,
crossorigin: "anonymous",
pathRewrite: {
"^/oss": "/api",
},
},
},
},
...
};
到这里,我们两个域名的跨域问题就解决啦~
访问服务器的域名限制问题
配置本地的 127.0.0.1
映射到 sincenir.com
前往本地的 C:\Windows\System32\drivers\etc
文件夹下,找到 hosts 文件,添加一行映射:
127.0.0.1 sincenir.com
需要注意:
#
是文件的注释,配置时,需要保证端口前无#
- 该文件需要以管理员身份打开、编辑、保存,可以通过 vscode 编辑保存,vscode 会提示你授权管理员权限
优化:hosts
管理工具
为了避免我们频繁修改 hosts
系统文件,进而导致的问题,我们可以通过 hosts
的管理工具来处理 hosts
文件。
- 下载
SwitchHosts
点击下载 - 安装并打开
- 添加
OSS
的host
- 配置
OSS
的host
- 启动
OSS
的host
SwitchHosts(hosts管理工具)git地址:github.com/oldj/Switch…
配置项目运行端口为 80
react
方案1:
在 node_modules\react-scripts\scripts\start.js
文件中,将下面代码替换:\
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 8080;
// 替换为
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 80;
方案2:
修改 package.json
中的 start
命令:
{
"scripts": {
"start": "set PORT=80 && craco start",
}
}
vue
配置 vue.config.js
module.exports = {
...
devServer: {
...
// 修改端口
port: 80,
// 老版本 vue(解决 Invalid Host header 问题)
disableHostCheck: true
// 新版本 vue(解决 Invalid Host header 问题)
historyApiFallback: true,
allowedHosts: ["test.fangcunyisheng.com"],
},
...
};
后期调试
配置完成后首先需要重启项目,然后不要打开启动后的 127.0.0.1:80
或者 localhost
的页面,打开 sincenir.com
,到这里就完成啦~
最后
这篇文章的主要讲的是带着问题如何解决问题,第二讲的是 OSS 跨域上传如何解决。
后续的文章会刨根问底的讲一讲跨域的由来、解决方案、及周边生态。
欢迎大家 点赞、关注、收藏~
原文链接:https://juejin.cn/post/7241938328840716325 作者:sincenir