目前的项目中大量运用前后端分离的结构,前端调用接口时,因为浏览器安全策略的限制,很容易产生跨域问题
跨域
出于浏览器的同源策略限制,浏览器会拒绝跨域请求
同源策略:请求时应该具有相同的协议、域名、端口,只要有一个不同就属于跨域
主机(https://cheriko.fun ) | 是否跨域 | 原因 |
---|
http://cheriko.fun | 是 | 协议不同 |
https://cheriko.fun:11451 | 是 | 端口不同 |
https://baidu.com | 是 | 域名不同 |
https://cheriko.fun/about/cheriko | 否 | \ |
跨域方式
- 前后端协商JSONP
- 前端解决,使用代理dev
- 后端解决,设置请求头
- 运维端解决,nginx代理
JSONP
HTML script标签的src属性,不受跨域访问限制,所以它可以发送跨域请求,但只能发送GET请求,而且不安全
使用此种方式,后端将会返回一个函数,这个函数必须提前在前端定义好,后端会把值注入到函数的参数里
前端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <script> const jsonp = (name) => { let script = document.createElement('script') script.src = 'http://localhost:3000/api/jsonp?callback=' + name document.body.append(script) return new Promise((resolve) => { window[name] = (data) => { resolve(data) } })
}
jsonp(`callback ${new Date().getTime()}`).then(res=> { console.log(res) }) </script>
|
后端:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import express from 'express'
const app = express();
app,get('/api/jsonp',(req, res)=> { const { callback } = req.query res.send(`${callback}('hello jsonp')`) })
app.listen(3000, ()=> { console.log('server is running') })
|
前端代理
纯前端代理解决跨域,需要用到构建工具(例如Webpack、Rollup、Vite等),只对开发环境有效
前端发送请求:
1 2 3
| fetch('/api/json').then(res=>res.json()).then(res=>{ console.log(res) })
|
Vite配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { defineConfig } from 'vite'
export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true, rewrite: (path)=> path.replace(/^\api/, '') } } } })
|
后端:
1 2 3 4 5 6 7 8 9 10 11
| import express from 'express'
const app = express()
app.get('/json',(req, res)=> { res.json({name:'yajue',age:24}) })
app.listen(3000, ()=> { console.log('server is running') })
|
后端设置请求头
后端只需要开启允许跨域即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import express from 'express'
const app = express();
app,get('/json',(req, res)=> { res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500') res.json({name:'yajue',age:24}) })
app.listen(3000, ()=> { console.log('server is running') })
|
Nginx反向代理
适合已上线的项目
前端发送请求:
1 2 3
| fetch('/api/json').then(res=>res.json()).then(res=>{ console.log(res) })
|
Nginx配置文件(在server块内):
1 2 3
| location /api/ { proxy_pass http://localhost:3000/; }
|
启动Nginx服务后,前端截取到/api/就会转发到http://localhost:3000/