讲一下我为啥要写:
跨域说的很多遍,看了很多文章,但总是用的时候就忘记怎么配置了,翻了好几篇文章,配置改了一遍又一遍还是发不出去请求,why? 其实你搜到的文章里面的配置大都是正确的,关键就是有些配置并没有理解,没有适合自己的项目,又盲目的不知道怎么改就去搜下一篇。
开发中跨域我这么做
在线上环境的跨域可以妥妥的交给运维,服务端,开发时如果遇到需要跨域那我们怎么做呢?我一般是通过配置Nginx来跟服务端做调试,因为开发的同事多了以后你总是把经常变的proxy的配置提交到Git上面我是不太喜欢的。其它的一些跨域文章如:jsonp,img,浏览器配置变量,改服务端配置等,你觉得方便你可以试试。😏我只用Nginx,真香!。
具体思路是这样的
先要说一些同源策略,同源策略是一个浏览器内的重要安全策略,限制非同源的脚本交叉访问。所谓的同源指的就是URL的三个主要部分:协议、域名/IP,端口。只有当这三者全部相同时即为同源。
当我们在浏览器访问我们做的网站地址时请求了资源服务器并返回了页面元素渲染在里浏览器里面,当我们的Web页面想数据服务器发送请求获取数据时由于两个服务并非同源就会禁止访问,因为对于我们开发时来说资源服务就相当于我们npm run dev
启动前端项目后的服务,需要访问的数据服务是在服务端同学的电脑上启动的服务。
重点来了,我们如果在浏览器发送的两种请求被一个中间商代理后,由中间商来向资源服务和数据服务交换信息。那这样在浏览器中不就变成同源了吗?
下图是我画包含Nginx的简易数据交换图:
搭建一个环境来演示一下:
构建一个服务端并提供一个post接口:
这个相对简单我们直接使用express
来启动一个3000端口的服务新增一个post路由即可:
const express = require("express"); const app = express(); const port = 3000; app.get("/", (req, res) => { res.send("Hello World!"); }); app.post("/api/user", (req, res) => { res.send("Got a POST request at /user"); }); app.listen(port, () => { console.log(`Example app listening on port ${port}`); }); 复制代码
构建一个静态资源服务来发起请求:
- 需要一个静态资源服务,我们使用
static-server
来实现:
const StaticServer = require('static-server'); const server = new StaticServer({ rootPath: '.', port: 5000, templates: { index: 'index.html', } }); server.start(function () { console.log('Server listening to', server.port); }); 复制代码
- 在当前目录创建名为
index.html
的首页,并使用axios
来发送请求:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>跨域演示</title> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <button @click="requestAPI">发送请求</button> <p>{{ content }}</p> <script type="module"> import { createApp } from 'https://unpkg.com/petite-vue?module' createApp({ content: "", requestAPI() { // nginx启动后需要将baseUrl切换到nginx监听的端口 axios.post('http://10.96.11.99:3000/api/user') .then((response) => { this.content = response.data; }) .catch((error) => { console.log('error :>> ', error); }); } }).mount() </script> </body> </html> 复制代码
注意:为了没有跨域限制,我们将axios
发送请求的baseURL
删除只保留接口部分,当我们通过5001端口访问页面后再发送的请求会自动携带5001端口的baseURL。
使用Nginx来做数据交换的中间商:
- 下载一个适合自己电脑环境的Nginx;
- 找到
conf/nginx.conf
文件,将内部默认的server
节点注释掉;
- 新增下面的这一片段:
- Nginx作为一个服务软件,我们监听5001端口,也就是启动后我们可以通过5001端口通信;
- 通过第一个
location /
配置我们将要访问的资源在哪?我们通过proxy_pass
将资源指向了前端项目启动的5000端口,这时候我们通过5001端口就可以看到我们的前端页面了; - 再通过第二个
location /api
配置可以拦截到我们请求中已/api
开始的资源请求后将通过proxy_pass
指向服务端项目启动的3000端口,IP自然就是服务端同学的IP。
server { # 启动Nginx监听端口 listen 5001; # 将通过5001端口访问路由请求跳转到proxy_pass配置 # proxy_pass:前端静态资源服务 location /{ proxy_pass http://localhost:5000; } # 将通过5001端口访问的携带api标识的请求跳转到proxy_pass配置 # proxy_pass:服务器接口地址 location /api{ proxy_pass http://10.96.11.99:3000/api; } } 复制代码
结尾总结:
不同的场景有不通的解决方案,我只是在开发联调时是这么做的。当你配置完后小概率还有被限制请求的情况,你就要考虑是否遇到多baseURL的情况,具体要调试的是哪个服务。观察浏览器发送的请求地址有没有被Nginx中间商接管。内容均是自己写的,有的概念描述也是自己的理解,有不当的地方还请指正。😘