Невозможно установить соединение с сервисами, используя CORS и cookies в приложении Next.js и Go Fiber в Docker-контейнерах

Рейтинг: 0Ответов: 1Опубликовано: 09.07.2023

Я разрабатываю приложение, состоящее из фронтенда на Next.js и бэкенда на Go Fiber. Приложение работает с MySQL и Redis, и все сервисы запускаются в отдельных Docker-контейнерах с помощью Docker Compose.

Я столкнулся с проблемой, когда запросы, связанные с куками, перестали работать после переноса приложения в Docker-контейнеры. Более конкретно, я получаю ошибку

Failed to load resource: net::ERR_NAME_NOT_RESOLVED

при попытке установить соединение с бэкендом, используя CORS и передачу cookies.

Вот некоторые части моего кода:

В файле main.go бэкенда, я настроил CORS для разрешения запросов с фронтенда:

app.Use(cors.New(cors.Config{
    AllowOrigins:     "http://frontend:3000",
    AllowHeaders:     "Origin, Content-Type, Accept",
    AllowMethods:     "GET, POST, PUT, DELETE",
    AllowCredentials: true,
}))

В файле .env фронтенда, я указал URL бэкенда:

NEXT_PUBLIC_BACKEND_URL=http://backend:5000
NEXT_PUBLIC_FRONTEND_URL=http://frontend:3000

Вот один из тех запросов, которые не срабатывают golang:

func Login(c *fiber.Ctx) error {
    
    var loginData *models.User
    if err := c.BodyParser(&loginData); err != nil {
        return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Не удается разобрать тело запроса"})
    }

    
    var user models.User
    if err := Connect.DB.Where("email = ?", loginData.Email).First(&user).Error; err != nil {
        return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Неправильный адрес электронной почты или пароль"})
    }



    if !utils.CheckPasswordHash(loginData.Password, user.Password) {
        return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Неправильный адрес электронной почты или пароль"})

    }

    
    fmt.Println("yes8")

    token, err := utils.CreateToken(&user)
    if err != nil {
        return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
    }

    cookie := new(fiber.Cookie)
    cookie.Name = "jwt"
    cookie.Value = token
    cookie.Expires = time.Now().Add(time.Hour * 24)
    cookie.HTTPOnly = true
    cookie.Secure = false
    c.Cookie(cookie)

    return c.JSON(fiber.Map{"message": "Авторизация успешна"})
}

Вот docker-compose.yml:

version: "3"
    services:
      frontend:
        build:
          context: ./frontend
          dockerfile: Dockerfile
        ports:
          - "3000:3000"
        volumes:
          - ./frontend:/app
        depends_on:
          - backend
          - mysql
          - redis
    
      backend:
        build:
          context: ./backend
          dockerfile: Dockerfile
        ports:
          - "5000:5000"
        volumes:
          - ./backend:/app
        depends_on:
          - mysql
          - redis
        command: wait-for-it mysql:3306 -- go run main.go
    
      mysql:
        image: mysql:latest
        ports:
          - "3306:3306"
        environment:
          - MYSQL_ROOT_PASSWORD=password_db
          - MYSQL_DATABASE=DATABASE
          - MYSQL_USER=name
          - MYSQL_PASSWORD=password
    
      redis:
        image: redis:latest
        ports:
          - "6379:6379"

В чем может быть проблема?
Мои мысли, что имена доменов отличаются, и из-за этого не получается отправить или принять cookies.

И можно будет перекинуть через hub docker на сервер vds, купить домен и поставить? Так может решиться?

теперь пытаюсь сделать через Nginx

    events {

}

http {
    server {
        listen 80;
        server_name codeza00.com;

        location / {
            proxy_pass http://frontend:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto $scheme; 
        }
    }

    server {
        listen 80;
        server_name api.codeza00.com;

        location / {
            proxy_pass http://backend:5000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto $scheme; 
        }
    }
}

Ответы

▲ 2Принят

Ошибка ERR_NAME_NOT_RESOLVED никак не связана ни с CORS, ни с куками. Ваш браузер пытается обратиться к http://backend:5000, но не может понять что такое backend. Это не удивительно - про backend знает только докер, а браузер работает снаружи докера.

Вы уже пробросили порт 5000 наружу - а значит, браузер может обратиться по этому порту, но ему нужно корректное доменное имя. При локальной отладке это будет localhost, в проде это будет доменное имя которое вы выберете.

Однако, контейнер frontend не может обратиться к бекенду по имени localhost, потому что порт пробрасывается докером только для внешних клиентов, но не для контейнеров. Поэтому вам надо настроить фронтенд так, чтобы обращения в SSR контексте и из браузера шли по разным адресам.

Насколько я знаю, в Next это настраивается примерно так:

NEXT_BACKEND_URL=http://backend:5000
NEXT_PUBLIC_BACKEND_URL=http://localhost:5000
NEXT_PUBLIC_FRONTEND_URL=http://localhost:3000

Только унесите это из .env файла! При запуске в контейнере переменные окружения должны настраиваться на уровне контейнера (в вашем случае - их можно прописать в docker-compose.yaml), иначе вам придётся собирать отдельные образы для каждого окружения, что является лишней работой.


Теперь про CORS. Origin - это то, с чем имеет дело браузер, а потому там тоже должен быть localhost. И не забудьте унести его тоже в переменную окружения!