Docker-Compose: пользовательский интерфейс Vue не подключается к Node js Express CORS API

Обновлено: я проверил вывод журнала внутри браузера и получил это сообщение: Ответ на предполетный запрос не проходит проверку контроля доступа: заголовок «Access-Control-Allow-Origin» имеет значение «http://127.0.0.1: 8888', что не соответствует указанному началу координат.

Второе редактирование: добавлена ​​дополнительная информация внизу сообщения.

Я, наверное, уже слеп к программированию, поэтому прошу о помощи. В настоящее время я работаю над приложением vue. У меня есть база данных (mariadb), интерфейс (vue js) и серверная часть/api (узел js express). Локально все работало нормально. Затем я захотел его докеризовать. Поэтому я использовал этот урок: https://www.bezkoder.com/docker-compose-react-nodejs-mysql/

Я сделал все, как в руководстве, кроме изменений в базе данных (имя базы данных и имена переменных), а затем запустил docker. В своих журналах я вижу, что мой сервер подключается к mariadb, так что, похоже, это работает. Я также могу получить доступ к своему приложению vue и щелкать по своему веб-сайту, как и ожидалось. Однако когда я пытаюсь ввести какие-то данные и отправить их в базу данных, ничего не происходит. Я даже не вижу журналов о запросе на публикацию в журналах API. Кажется, возникла ошибка соединения между пользовательским интерфейсом и API, но я не могу найти ошибку.

Я использовал руководство и проверил имена переменных, которые я изменил, но изменений нет.

Моя структура папок: введите сюда описание изображения

Мой файл .env

    MYSQLDB_USER=root
    MYSQLDB_ROOT_PASSWORD=root
    MYSQLDB_DATABASE=rgs
    MYSQLDB_LOCAL_PORT=3307
    MYSQLDB_DOCKER_PORT=3306

    NODE_LOCAL_PORT=6868
    NODE_DOCKER_PORT=8080

    CLIENT_ORIGIN=http://127.0.0.1:8888
    CLIENT_API_BASE_URL=http://127.0.0.1:6868/api/users

    VUE_LOCAL_PORT=8888
    VUE_DOCKER_PORT=80

Мой compose.yaml

  services: #individual services in isolated containers. Our application has three services
      mariadb:
        image: mariadb
        restart: unless-stopped
        env_file: ./.env
        environment:
          - MYSQL_ROOT_PASSWORD=$MYSQLDB_ROOT_PASSWORD
          - MYSQL_DATABASE=$MYSQLDB_DATABASE
        ports:
          - $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
        volumes: #named volumes that keeps our data alive after restart / map volume folders
          - db:/var/lib/mysql
        networks: #facilitate communication between containers
          - backend

      api: #nodejs
        depends_on:
          - mariadb
        build: ./api
        restart: unless-stopped
        env_file: ./.env
        ports:
        - $NODE_LOCAL_PORT:$NODE_DOCKER_PORT
        environment: #provide setting using environment variables
          - DB_HOST=mariadb
          - DB_USER=$MYSQLDB_USER
          - DB_PASSWORD=$MYSQLDB_ROOT_PASSWORD
          - DB_NAME=$MYSQLDB_DATABASE
          - DB_PORT=$MYSQLDB_DOCKER_PORT
          - CLIENT_ORIGIN=$CLIENT_ORIGIN
        networks:
          - backend
          - frontend

      ui: #vue
        depends_on:
          - api #to be changed for kubernetes tests
        build:
          context: ./ui
          args: #add build arguments – environment variables accessible only during the build process
            - VUE_APP_API_BASE_URL=$CLIENT_API_BASE_URL
        ports: #You should note that the host port (LOCAL_PORT) and the container port (DOCKER_PORT) is different. Networked service-to-service communication uses the container port, and the outside uses the host port
          - $VUE_LOCAL_PORT:$VUE_DOCKER_PORT
        networks:
          - frontend

  volumes: 
    db:

  networks:
    backend:
    frontend:

Мой http-common.js

  import axios from "axios";

  export default axios.create({
    baseURL: process.env.VUE_APP_API_BASE_URL || "http://localhost:8080/api/users", //Die eigene URL des Clienten also mir selbst
    headers: {
      "Content-type": "application/json"
    }
  });

Мой Docker-файл VUE UI

    # Stage 1
    FROM node:14 as build-stage

    WORKDIR /ui
    COPY package.json .
    RUN npm install
    COPY . .

    ARG VUE_APP_API_BASE_URL
    ENV VUE_APP_API_BASE_URL=$VUE_APP_API_BASE_URL

    RUN npm run build

    # Stage 2
    FROM nginx:1.17.0-alpine

    COPY --from=build-stage /ui/dist /usr/share/nginx/html
    EXPOSE $VUE_DOCKER_PORT

    CMD nginx -g 'daemon off;'

Мой сервер Dockerfile

  # syntax=docker/dockerfile:1

  ARG NODE_VERSION=20.11.1

  FROM node:${NODE_VERSION}-alpine

  # Use production node environment by default.
  ENV NODE_ENV production

  WORKDIR /api
  #copy package.json file to the container
  COPY package.json . 
  RUN npm install
  #copies all the files inside the project directory to the container
  COPY . .
  CMD npm start

Мой сервер js

  require("dotenv").config();
  const express = require("express"); // Used to build the Rest api
  const cors = require("cors");

  const app = express();

  var corsOptions = {
    origin: process.env.CLIENT_ORIGIN || "http://localhost:8081" // Server end point - woher stammt die Anfrage, port muss stimmen
  };

  app.use(cors(corsOptions));

  // parse requests of content-type - application/json
  app.use(express.json());

  // parse requests of content-type - application/x-www-form-urlencoded
  app.use(express.urlencoded({ extended: true }));

  const db = require("./app/models");
  db.sequelize.sync()
    .then(() => {
      console.info("Synced db.");
    })
    .catch((err) => {
      console.info("Failed to sync db: " + err.message);
    });


  // FOR DEVELOPEMENT ONLY v
  /*db.sequelize.sync({ force: true }).then(() => {
    console.info("Drop and re-sync db.");
  });*/
  // FOR DEVELOPEMENT ONLY ^ 

  // simple route
  app.get("/", (req, res) => {
    res.json({ message: "Welcome to rgs." });
  });

  require("./app/routes/user.routes.js")(app);

  // set port, listen for requests
  const PORT = process.env.NODE_DOCKER_PORT || 8080;
  app.listen(PORT, () => {
    console.info(`Server is running on port ${PORT}.`);
  });

Мой db.config.js

    module.exports = {
      HOST: process.env.DB_HOST,
      USER: process.env.DB_USER,
      PASSWORD: process.env.DB_PASSWORD,
      DB: process.env.DB_NAME,
      port: process.env.DB_PORT,
      dialect: "mariadb",
      pool: {
        max: 5,
        min: 0,
        acquire: 30000,
        idle: 10000
      }
    }; 

Второе редактирование: я изменил CLIENT_ORIGIN=http://172.0.0.1:8888 на CLIENT_ORIGIN=http://localhost:8888.

Это приводит к еще одной ошибке. Опять же, с большинством страниц, которые я вызываю, все в порядке, но когда я пытаюсь открыть страницу с полями ввода, теперь получаю ошибку: ресурс не найден:

    Failed to load resource: the server responded with a status of 404 (Not Found)
    vue-router.mjs:3479 
 ChunkLoadError: Loading chunk 578 failed.
(error: http://localhost:8888/js/578.1a9ac476.js)
    at t.f.j (app.6e12f49f.js:1:5420)
    at app.6e12f49f.js:1:2555
    at Array.reduce (<anonymous>)
    at t.e (app.6e12f49f.js:1:2520)
    at component (app.6e12f49f.js:1:391)
    at Ue (vue-router.mjs:2101:40)
    at vue-router.mjs:3309:22

Часть моего App.vue

    <script setup>
    import HeaderLogin from '@/components/AllSitesHeaderLogin.vue'
    import HeaderLoggedIn from '@/components/AllSitesHeaderLoggedIn.vue'
...
</script>

<template>
  <!-- <div v-if = "!loggedIn">  -->
  <div v-if = "true"> 
    <HeaderLogin></HeaderLogin>
  </div>

Мой AllSitesHeaderВойти

    <template>
  <header>
    <nav>
      <router-link to = "/">Home</router-link> |
      <router-link to = "/forum">Forum</router-link> |
      <router-link to = "/add">Login</router-link> 
    </nav>
  </header>
</template>

<script>
export default {
  name: 'AllSitesHeaderLogin',
}
</script>

Мой router.js

    import { createWebHistory, createRouter } from "vue-router";

const routes = [
  { path: '/:pathMatch(.*)*', 
    component: () => import("./views/HomeView.vue") 
  },
  {
    path: "/",
    alias: "/home",
    name: "home",
    component: () => import("./views/HomeView.vue")
  },
  {
    path: "/login",
    name: "login",
    component: () => import("./views/LoginView.vue")
  },
  {
    path: "/add",
    name: "add",
    component: () => import("./views/RegisterView.vue")
  },
  {
    path: "/about",
    name: "about",
    component: () => import("./views/AboutView.vue")
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

Не показано, по какому URL вы переходите при получении ошибки.

Estus Flask 21.04.2024 22:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

После изменения адреса с 127.0.0.1 на localhost (см. мои примечания к редактированию) мне пришлось очистить кеш. Это был последний шаг, теперь все работает.

Спасибо, Эстус Фласк, потому что я проверил свои маршруты и тоже нашел там ошибку.

Другие вопросы по теме