proxy
跨域的产生
一般项目的开发都是采用的是前后端分离的模式,采用这种方式在团队开发中可以大大降低开发人员的技术储备,从而加快开发周期
然后前后端分离也有座大山卡在那里 -- 跨域问题 (因为浏览器同源策略 致使前端请求无法达到后端)
如何解决跨域问题
跨域可以在前端解决也可以在后端解决
- 前端: proxy代理,可以使用你可以使用的各种代理工具, eg: nginx/caddy/rinetd或create-react-app设置
- 后端: 中间件
为了加快进度,前端同学不必等后端吧接口都开发完了才开始
先约定好接口,然后mock数据,并行开发
前端
1.使用mock服务器
mock数据的方式有很多,这里推荐一款工具serve,它是一款静态服务器
使用方法很简单:使用serve
命令就可以
#install
sudo npm i serve -g
#启动
serve
前端开发的时候再把api请求转发到mock服务器即可
mock服务器的使用
随便找个文件夹,以react为例,然后react下创建一个api文件夹(一般api会以/api
开头),api下放个json文件,这里以data.json
为例:
{
"name": "Scott",
"age": 18
}
这时在react目录下启动serve
命令(不指定端口,端口随机,每次启动mock server端口都不一样)
需要注意的是,如果修改mock数据,需要重启静态服务器才能生效
更多serve的使用:
$ serve --help
serve - Static file serving and directory listing
USAGE
$ serve --help
$ serve --version
$ serve folder_name
$ serve [-l listen_uri [-l ...]] [directory]
By default, serve will listen on 0.0.0.0:3000 and serve the
current working directory on that address.
Specifying a single --listen argument will overwrite the default, not supplement it.
OPTIONS
--help Shows this help message
-v, --version Displays the current version of serve
-l, --listen listen_uri Specify a URI endpoint on which to listen (see below) -
more than one may be specified to listen in multiple places
-p Specify custom port
-d, --debug Show debugging information
-s, --single Rewrite all not-found requests to `index.html`
-c, --config Specify custom path to `serve.json`
-C, --cors Enable CORS, sets `Access-Control-Allow-Origin` to `*`
-n, --no-clipboard Do not copy the local address to the clipboard
-u, --no-compression Do not compress files
--no-etag Send `Last-Modified` header instead of `ETag`
-S, --symlinks Resolve symlinks instead of showing 404 errors
--ssl-cert Optional path to an SSL/TLS certificate to serve with HTTPS
--ssl-key Optional path to the SSL/TLS certificate's private key
--ssl-pass Optional path to the SSL/TLS certificate's passphrase
--no-port-switching Do not open a port other than the one specified when it's taken.
ENDPOINTS
Listen endpoints (specified by the --listen or -l options above) instruct serve
to listen on one or more interfaces/ports, UNIX domain sockets, or Windows named pipes.
For TCP ports on hostname "localhost":
$ serve -l 1234
For TCP (traditional host/port) endpoints:
$ serve -l tcp://hostname:1234
For UNIX domain socket endpoints:
$ serve -l unix:/path/to/socket.sock
For Windows named pipe endpoints:
$ serve -l pipe:\\.\pipe\PipeName
2.直接将mock数据放到react项目的public文件夹下
这种方法最暴力
启动react
3.将代理转发到mock server
proxy将代理转发到mock server -- 新版本是失败的目前还在尝试
默认情况下create-react-app
的package.json
长这样
如果要配置代理,需要添加一个proxy的节点
"proxy":{
"/api": {
"target":"http://localhost:59898"
}
}
意思是如果前端请求路径含有/api
,那么就把它转发到 http://localhost:59898
指定端口转发
serve -p port
将react api的接口转发到http://localhost:8888
package.json 配置节点:
"proxy":{
"/api": {
"target":"http://localhost:8888"
}
}
启动react 报错了
4.setupProxy.js
在src目录下创建setupProxy.js
(注意必须是这个文件名, create-react-app
在启动时会自动加载这个配置文件)
npm i http-proxy-middleware -D
内容如下:
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api', //api prefix
createProxyMiddleware({
target: 'http://127.0.0.1:8900', //admin
changeOrigin: true,
})
);
};
后端
以golang为例, 写个中间件,加入以下请求头即可
package middleware
import (
"github.com/gin-gonic/gin"
)
func AllowCrossOrigin() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
// 必须,接受指定域的请求,可以使用*不加以限制,但不安全
//c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Origin", c.GetHeader("Origin"))
fmt.Println(c.GetHeader("Origin"))
// 必须,设置服务器支持的所有跨域请求的方法
c.Header("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS")
// 服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段
c.Header("Access-Control-Allow-Headers", "Content-Type, Content-Length, Token, X-Requested-With") //X-Requested-With 图片上传
// 可选,设置XMLHttpRequest的响应对象能拿到的额外字段
c.Header("Access-Control-Expose-Headers", "Access-Control-Allow-Headers, Token")
// 可选,是否允许后续请求携带认证信息Cookir,该值只能是true,不需要则不设置
c.Header("Access-Control-Allow-Credentials", "true")
// 放行所有OPTIONS方法
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}