Edit: I checked the Log Output inside the Browser and got this message: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://127.0.0.1:8888' that is not equal to the supplied origin.
2nd Edit: Added More Information at the bottom of the post
I'm probably code blind by now, so this is why I am begging for help. I am currently working on a vue app. I have a database (mariadb), a frontend (vue js) and a backend/api (node js express). Locally, it worked fine. Then I wanted to dockerize it. So I used this tutorial: https://www.bezkoder.com/docker-compose-react-nodejs-mysql/
I did everything as in the tutorial, except changes to the database (name of the db and var names) and then I started docker. I can see in my logs, that my server connects to mariadb, so that seems to work. I can also access my vue application and click around on my website as expected. Yet, when I try to give some input and send it to the database, nothing happens. I don't even see any logs about a post request in my api logs. So there seems to be a connections error between ui and api but I cannot find the mistake.
I used the tutorial and checked the var names that I changed, but there is no change.
My Folder Structure: enter image description here
My .env file
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
My 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:
My 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"
}
});
My VUE UI Dockerfile
# 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;'
My server 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
My server 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.log("Synced db.");
})
.catch((err) => {
console.log("Failed to sync db: " + err.message);
});
// FOR DEVELOPEMENT ONLY v
/*db.sequelize.sync({ force: true }).then(() => {
console.log("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.log(`Server is running on port ${PORT}.`);
});
My 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
}
};
Second Edit: I changed CLIENT_ORIGIN=http://172.0.0.1:8888 to CLIENT_ORIGIN=http://localhost:8888
This resulter in another error. Again, most of the pages I am calling are fine, but when I try to open the page with the input fields, now I get a resource not found error:
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
Part of my 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>
My AllSitesHeaderLogin
<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>
My 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;
After changing the address from 127.0.0.1 to localhost (see my Edit notes) I had to clean my cache. This was the final step, now it works.
Thank you, Estus Flask, because I checked my routes and also found an error there.