在 docker 网络内的开发环境中以及从 docker 主机使用 axios

问题描述 投票:0回答:1

我正在构建一个 Web 应用程序,它应该在不同的 docker 容器上运行:

version: "3.8"
services:
  backend:
    build: ./backend
    container_name: app-be
    ports:
      - 8000:8000
    volumes:
      - ./backend:/app

  frontend:
    build: ./frontend
    container_name: app-fe
    ports:
      - 5173:5173
    volumes:
      - ./frontend:/app

  test:
    build: ./test
    container_name: app-e2e
    command: npx cypress run -b firefox
    environment:
      - CYPRESS_baseUrl=http://frontend:5173
    tty: true
    volumes:
      - ./test:/app

前端是一个vuejs应用程序,我尝试通过axios访问后端;当启动一切时,该应用程序也会经过 cypress 的测试。但我也想在本地看到我的改变;这造成了我的问题:

为了从主机访问后端,axios 需要使用 http://localhost:8000 作为后端地址,但这样 Cypress 测试当然会失败;对于这些 axios 需要访问 http://backend:8000 ,这对于主机来说也是未知的。不过我希望两种情况都涵盖

export default {
  data() {
    return { msg: '' };
  },
  methods: {
    getMessage() {
      axios.get('http://backend:8000/') // <-- change to localhost when running in browser
           .then((res) => { this.msg = res.data; })
           .catch((error) => { console.error(error);});
    },
  },
  created() {
    this.getMessage();
  },
};

来自后端开发,我通常会使用根据环境获取的不同环境文件来解决类似的问题 - 但在这种情况下 axios 在客户端上作为 JavaScript 运行,所以这不能在服务器端解决,因为它是使用相同的服务器。当然,我们可以改变这一点 - 运行两个前端实例 - 一个用于 cypress 测试,另一个用于本地开发,并使用不同的环境变量启动它们,但这感觉有点脏。

另一个解决方法是将行

127.0.0.1 backend
添加到系统
/etc/hosts
,但我对这个解决方案也感觉不好;对我来说,使用 docker 的一个主要好处是让其他人只需下载项目并运行它,而无需在本地计算机上安装任何内容。需要 root 权限来更改基本的系统配置在某种程度上违背了这个想法。

所以我的问题: 有没有更好的方法来解决我没有看到的这个问题?或者这真的是唯一可用的两个选择吗?

docker axios vuejs3 cypress local
1个回答
0
投票

所以我找到了一个我满意的更好的解决方案,感谢David Maze的评论,但它涉及更多的工作。

添加 nginx 代理后

如所解释的,即

    添加到 docker-compose:
proxy: build: ./proxy container_name: app-prx ports: - 80:80

  • ./proxy/
     中引入新的 Dockerfile:
来自 nginx:1.25.2-alpine 复制 default.conf /etc/nginx/conf.d

  • ./proxy/default.conf
    中引入新的nginx配置文件:
服务器 { 听80; 服务器名称本地主机; 地点 / { proxy_pass http://frontend:5173/; } 位置/api/ { proxy_pass http://backend:8000/; } }
然后修复Cypress访问

http://proxy/

并将前端对后端的调用从
http://backend:8000/
修复为
/api/
,项目实际上会在本地浏览器中显示正确的结果。然而,我的柏树测试失败并出现一条奇怪的消息:

指定了无效或非法的字符串

事实证明,当在本地查看控制台时,您会收到一条更有用的消息:

Firefox 无法与位于 ws://localhost/ 的服务器建立连接。 未捕获(承诺中)DOMException:指定了无效或非法字符串 setupWebSocet client.ts:77 后备 client.ts: 42 (...)
我不知道为什么会发生这种情况,但是由于某种原因,在添加nginx时,vite需要在

vite.config.js

中指定一个websocket:

export default defineConfig({ plugins: [ vue(), ], (...) server: { hmr: { port: 5173 host: "localhost", protocol: "ws", }, }, })

NB:添加所有三个组件非常重要 - 我首先遗漏了端口,这导致了与之前相同的错误(因此我花了更长的时间才弄清楚这一点)。根据您启动前端的方式,这可能会导致新的错误:

端口 5173 正在使用中,请尝试另一个端口。 启动开发服务器时出错: 错误 [ERR_SERVER_ALREADY_LISTEN]:Listen 方法已被多次调用而未关闭。
在这种情况下,请确保您使用指定的端口显式启动前端。就我而言,我在前端的 

Dockerfile

 末尾执行此操作:

CMD [“npm”,“运行”,“dev”,“--”,“--主机”,“0.0.0.0”,“--端口”,“5173”]
对我来说,与我上面介绍的其他两种设置相比,这是一个更加优越的设置,原因有 4 个:

    它解决了我最初的问题,即它可以在 docker 内部和主机上运行,而无需更改主机。
  1. 它还简化了前端中的所有路由(在我创建 axios 实例作为帮助程序来设置
  2. baseURL: 'http://backend:8000'
     并将其导出到我的所有组件之前 - 不再需要了)。
  3. 一旦投入生产,你可能就需要一个 nginx。
  4. 鉴于 3,您不会生成“无用”的 docker 容器,这些容器只是具有不同环境设置的其他容器的副本,只是为了满足客户端浏览器脚本。
© www.soinside.com 2019 - 2024. All rights reserved.