When running my React app in Docker using Nginx as a reverse proxy, I get an error when connecting to WebSocket. I get an error message:
WebSocket connection to 'ws://backend:7000/api/getData' failed: WebSocket error
When running my React app in Docker using Nginx as a reverse proxy, I get an error when connecting to WebSocket. I get an error message:
WebSocket connection to ‘ws://backend:7000/api/getData’ failed: WebSocket error
However, locally everything works perfectly. The problem only occurs in Docker.
The backend (Go) is configured to handle WebSocket requests and also works with Redis to receive data.
When trying to connect React client code to a WebSocket server that is located in a Docker container, an error occurs.
How to fix this problem?
here is my docker-compose:
version: '3'
services:
frontend:
build:
context: ./front/app
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
NODE_ENV: production
restart: always
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "7000:7000"
restart: always
bot:
build:
context: ./bot_crypto/crypto
dockerfile: Dockerfile
restart: always
redis:
image: redis
ports:
- "6379:6379"
restart: always
nginx:
image: nginx
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- frontend
- backend
- bot
restart: always
nginx:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://frontend:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://backend:7000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
frontend:
import { name_table } from "data/data";
import { useEffect, useState } from "react";
import { DataGetProps } from "interfaces/data.props";
import Filter from "components/filter/filter";
import NProgress from "nprogress";
const Content = () => {
const [data, setData] = useState<DataGetProps[]>([]);
const [socket, setSocket] = useState<WebSocket | null>(null);
const [time, setTime] = useState<string>("");
const [filterData, setFilterData] = useState<DataGetProps[]>([])
const [stateFilter, setStateFilter] = useState<boolean>(false)
const [stateFilterNum, setFilterNum]=useState<number>(0)
useEffect(() => {
const newSocket = new WebSocket("ws://backend:7000/api/getData");
setSocket(newSocket);
return () => {
newSocket.close();
};
}, []);
useEffect(() => {
if (!socket) return;
socket.onmessage = (event) => {
NProgress.start();
const message = JSON.parse(event.data);
setData(message.data);
setTime(new Date().toLocaleString());
setStateFilter(true)
NProgress.done();
console.log(message);
};
socket.onerror = (error) => {
console.error("WebSocket error:", error);
};
return () => {
socket.close();
};
}, [socket]);
return (
<div className="min-h-screen flex items-center justify-center">
<div className="max-w-max grid grid-cols-1 gap-4 px-4">
<div className={"text-center"} > Обновление: {time}</div>
<Filter data={data} setFilterData={setFilterData} stateFilter={stateFilter} setStateFilter={setStateFilter} stateFilterNum={stateFilterNum} setFilterNum={setFilterNum}/>
<div className={"grid grid-cols-6 gap-4"}>
{name_table && name_table.map((item) => (
<div key={item.id} className="p-4 bg-gray-200 text-center rounded">
<div className={"text-black font-bold"}>{item.name}</div>
</div>
))}
</div>
{filterData && filterData.map((item) => (
<div key={item.id} className={"grid grid-cols-6 gap-4"}>
<div className="p-4 bg-gray-200 text-center rounded">{item.symbol}</div>
<div className="p-4 bg-gray-200 text-center rounded">{item.exchange1}</div>
<div className="p-4 bg-gray-200 text-center rounded">{item.price1}</div>
<div className="p-4 bg-gray-200 text-center rounded">{item.exchange2}</div>
<div className="p-4 bg-gray-200 text-center rounded">{item.price2}</div>
<div className="p-4 bg-gray-200 text-center rounded">{item.spread}</div>
</div>
))}
</div>
</div>
);
};
export default Content;
Golang:
package main
import (
"encoding/json"
"fmt"
"github.com/codeza-org/backend_crypto/connect"
"github.com/go-redis/redis/v8"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/websocket/v2"
"time"
)
type Comparison struct {
ID string `json:"id"`
Symbol string `json:"symbol"`
Exchange1 string `json:"exchange1"`
Price1 float64 `json:"price1"`
Exchange2 string `json:"exchange2"`
Price2 float64 `json:"price2"`
Spread float64 `json:"spread"`
}
var client *redis.Client
func main() {
var err error
client, err = connect.Connect()
if err != nil {
panic(err)
}
defer client.Close()
app := fiber.New()
app.Use(cors.New(cors.Config{
AllowOrigins: "http://frontend:3000",
}))
app.Use("api/getData", func(c *fiber.Ctx) error {
if websocket.IsWebSocketUpgrade(c) {
return c.Next()
}
return fiber.ErrUpgradeRequired
}, websocket.New(getData))
app.Post("api/data", data)
app.Listen(":7000")
}
func data(c *fiber.Ctx) error {
var comparisons []Comparison
if err := c.BodyParser(&comparisons); err != nil {
return err
}
jsonData, err := json.Marshal(comparisons)
if err != nil {
return err
}
err = client.Set(client.Context(), "data", jsonData, 0).Err()
if err != nil {
return err
}
fmt.Println("Данные успешно записаны в Redis")
return c.JSON(fiber.Map{
"message": "Данные успешно получены и обработаны",
})
}
func getData(c *websocket.Conn) {
for {
fmt.Println(1)
if c == nil {
fmt.Println("Соединение WebSocket закрыто")
return
}
val, err := client.Get(client.Context(), "data").Result()
if err != nil {
fmt.Println("Ошибка при получении данных из Redis:", err)
return
}
var comparisons []Comparison
err = json.Unmarshal([]byte(val), &comparisons)
if err != nil {
fmt.Println("Ошибка при разборе данных JSON:", err)
return
}
data, err := json.Marshal(fiber.Map{"data": comparisons})
if err != nil {
fmt.Println("Ошибка при преобразовании данных в JSON:", err)
return
}
err = c.WriteMessage(websocket.TextMessage, data)
if err != nil {
fmt.Println("Ошибка при отправке данных через WebSocket:", err)
return
}
из Redis
time.Sleep(5 * time.Second)
}
}