写点什么

开发中遇到跨域我选择这么做

作者:小鑫同学
  • 2022-10-13
    北京
  • 本文字数:2352 字

    阅读完需:约 8 分钟

开发中遇到跨域我选择这么做

大家好,我是小鑫同学。一位从事过 Android 开发混合开发,现在长期从事前端开发的编程爱好者,我觉得在编程之路上最重要的是知识的分享,所谓三人行必有我师。所以我开始在社区持续输出我所了解到、学习到、工作中遇到的各种编程知识,欢迎有想法、有同感的伙伴加我fe-xiaoxin微信交流~

讲一下我为啥要写:

跨域说的很多遍,看了很多文章,但总是用的时候就忘记怎么配置了,翻了好几篇文章,配置改了一遍又一遍还是发不出去请求,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}`);});
复制代码

构建一个静态资源服务来发起请求:

  1. 需要一个静态资源服务,我们使用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);});
复制代码


  1. 在当前目录创建名为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 来做数据交换的中间商:

  1. 下载一个适合自己电脑环境的Nginx

  2. 找到conf/nginx.conf文件,将内部默认的server节点注释掉;

  3. 新增下面的这一片段:

  4. Nginx 作为一个服务软件,我们监听 5001 端口,也就是启动后我们可以通过 5001 端口通信;

  5. 通过第一个location / 配置我们将要访问的资源在哪?我们通过proxy_pass将资源指向了前端项目启动的 5000 端口,这时候我们通过 5001 端口就可以看到我们的前端页面了;

  6. 再通过第二个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 中间商接管。内容均是自己写的,有的概念描述也是自己的理解,有不当的地方还请指正。😘




欢迎关注我的公众号“前端小鑫同学”,原创技术文章第一时间推送。

发布于: 刚刚阅读数: 3
用户头像

小鑫同学

关注

⚡InfoQ签约作者 2018-12-10 加入

还未添加个人简介

评论

发布
暂无评论
开发中遇到跨域我选择这么做_前端_小鑫同学_InfoQ写作社区