Nuxt. js SSR с Nest API, развернутым в AWS в контейнере Docker - PullRequest
0 голосов
/ 04 февраля 2020

Я перепробовал примерно 5 миллионов вариантов темы здесь, а также провел много времени, просматривая документы Nuxt, и я не могу получить Nuxt SSR с бэкэндом Nest, работающим при развертывании в контейнере docker в AWS. Ниже моя текущая установка. Пожалуйста, дайте мне знать, если я что-то пропустил.

Вот ошибки, которые я получаю:

https://www.noticeeverythingcreative.com/contact Этот маршрут делает запрос POST для мета страницы в https://www.noticeeverythingcreative.com/api/contact/meta в методе asyncData компонента. Это приводит к большой старой ошибке от Ax ios. Ниже приведена часть, которая, на мой взгляд, актуальна, но, если вам нужно больше, дайте мне знать.

{
  errno: 'ECONNREFUSED',
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: 'xxx.xx.x.x', // IP Address of the docker container
  port: 443,
  config: {
    url: 'https://www.noticeeverythingcreative.com/api/contact/meta',
    method: 'post',
    headers: {
      Accept: 'application/json, text/plain, */*',
      connection: 'close',
      'x-real-ip': 'xx.xxx.xxx.xxx', // My IP
      'x-forwarded-for': 'xx.xxx.xxx.xxx', // My IP
      'x-forwarded-proto': 'https',
      'x-forwarded-ssl': 'on',
      'x-forwarded-port': '443',
      pragma: 'no-cache',
      'cache-control': 'no-cache',
      'upgrade-insecure-requests': '1',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36',
      'sec-fetch-user': '?1',
      'sec-fetch-site': 'same-origin',
      'sec-fetch-mode': 'navigate',
      'accept-encoding': 'gzip, deflate',
      'accept-language': 'en-US,en;q=0.9',
      'Content-Type': 'application/json'
    },
    baseURL: 'https://www.noticeeverythingcreative.com'
  }

Вот соответствующая часть моего nuxt.config.js:

mode: 'universal',
srcDir: './src',
rootDir: './',
modules: ['@nuxtjs/axios'],
// NOTE: I get the same errors if I leave this block out
server: {
    host: '0.0.0.0',
    port: 3002
},

Когда я развернусь, я используйте Dockerfile, который копирует все необходимые файлы из каталога моего проекта в контейнер, запускает yarn install, предоставляет порт 3002, запускает yarn build.prod и заканчивается CMD ["yarn", "start"] (соответствующие сценарии package.json см. ниже).

"scripts": {
    "clean.nuxt": "rimraf .nuxt",
    "build.client": "nuxt build",
    "build.server": "tsc -p tsconfig.server.json", // Transpile TypeScript from `src/server` into `.nuxt/api`
    "build.prod": "run-s clean.nuxt build.client build.server",
    "start": "cross-env NODE_ENV=production node .nuxt/api/index.js",
}

Образ docker создается локально и отправляется в репозиторий ECR. Затем я S SH на свой сервер и запускаю docker-compose up -d с этим файлом compose:

version: '3.2'

services:
  my_service:
  image: link/to/my/image:${TAG:-prod}
  container_name: my_container
  hostname: www.noticeeverythingcreative.com
  restart: unless-stopped

ports:
  # Http Port
  - 3002:3002

networks:
  - web-network # External (the actual compose file also has the corresponding networks block at the bottom)

environment:
  - NODE_ENV=production
  - API_URL=https://www.noticeeverythingcreative.com
  - HOST=www.noticeeverythingcreative.com
  - PORT=3002
  - VIRTUAL_PORT=3002 

Вот мой серверный контроллер, который обрабатывает рендеринг Nuxt:

src / server / app / nuxt.controller.ts

import { Controller, Get, Request, Response } from '@nestjs/common';
import { join, resolve } from 'path';
import * as config from 'config';

const { Builder, Nuxt } = require('nuxt');
const nuxtConfig = require(join(resolve(), 'nuxt.config.js'));

@Controller()
export class NuxtController
{
    nuxt:any;

    constructor()
    {
        this.nuxt = new Nuxt(nuxtConfig);
        const Env = config as any;

        // Build only in dev mode
        if (Env.name === 'development')
        {
            const builder = new Builder(this.nuxt);
            builder.build();
        }
        else
        {
            this.nuxt.ready();
        }

    }

    @Get('*')
    async root(@Request() req:any, @Response() res:any)
    {
        if (this.nuxt)
        {
            return await this.nuxt.render(req, res);
        }
        else
        {
            res.send('Nuxt is disabled.');
        }
    }
}

Вот реализации клиентского компонента контактов asyncData и head:

async asyncData(ctx:any)
{
    // fetch page meta from API
    try
    {
        const meta = await ctx.$axios(<any>{
            method: 'post',
            url: `${ ctx.env.apiHost }/contact/meta`,
            headers: { 'Content-Type': 'application/json' }
        });

        return { meta: meta.data };
    }
    catch (error)
    {
        // Redirect to error page or 404 depending on server response
        console.log('ERR: ', error);
    }
}

head()
{
    return this.$data.meta;
}

Проблемы, которые я Я имею дело только в производственной среде на производственном хосте. Локально я могу запустить yarn build.prod && cross-env NODE_ENV=development node .nuxt/api/index.js, и приложение работает и отображает без ошибок.

Обновление

Если я разрешу приложению Nuxt работать на localhost внутри контейнера docker, я столкнусь с противоположной проблемой. Например, если я изменю свой блок nuxt.config. js server и ax ios на

server: {
    port: 3002, // default: 3000,
},
axios: {
    baseURL: 'http://localhost:3002'
}

и изменим запрос на:

const meta = await ctx.$axios(<any>{
    method: 'post',
    // NOTE: relative path here instead of the absolute path above
    url: `/api/contact/meta`,
    headers: { 'Content-Type': 'application/json' }
});

return { meta: meta.data };

A fre sh нагрузка https://www.noticeeverythingcreative.com/contact делает хорошо. Это можно подтвердить, просмотрев исходный код страницы и убедившись, что заголовок обновлен и что нет ошибок консоли. Однако, если вы загрузите домашнюю страницу (https://www.noticeeverythingcreative.com) и нажмете ссылку контакта в навигационной панели, вы увидите POST http://localhost:3002/api/contact/meta net::ERR_CONNECTION_REFUSED.

ПРИМЕЧАНИЕ. Эта версия развернута на момент последнего редактирования этого вопроса.

1 Ответ

0 голосов
/ 04 февраля 2020

Я придумала решение, но оно мне не нравится, поэтому, если у кого-то есть что-то лучше, пожалуйста, напишите.

Я получил его, позволив приложению Nuxt работать на локальном хосте внутри контейнер docker, но отправляет http запросы к фактическому хосту (например, https://www.noticeeverythingcreative.com/whatever).

Итак, в nuxt.config.js:

// The server and axios blocks simply serve to set the port as something other than the default 3000
server: {
    port: 3002, // default: 3000,
},
axios: {
    baseURL: 'http://localhost:3002'
},
env: {
    apiHost: process.env.NODE_ENV === 'production' ?
        'https://www.noticeeverythingcreative.com/api' :
        'http://localhost:3002/api'
} 

В docker-compose.yml я удалил все, что сделало бы для хоста что угодно, кроме localhost, а также все переменные env, на которые рассчитывает nuxt ( главным образом потому, что я не могу понять, как они работают в Nuxt, за исключением того, что это не так, как я ожидал):

version: '3.2'

services:
  my_service:
  image: link/to/my/image:${TAG:-prod}
  container_name: my_container
  # REMOVED
  # hostname: www.noticeeverythingcreative.com
  restart: unless-stopped

ports:
  # Http Port
  - 3002:3002

networks:
  - web-network # External (the actual compose file also has the corresponding networks block at the bottom)

environment:
  # REMOVED
  # - API_URL=https://www.noticeeverythingcreative.com
  # - HOST=www.noticeeverythingcreative.com
  - NODE_ENV=production
  - PORT=3002
  - VIRTUAL_PORT=3002

И при создании запросов API:

// NOTE: ctx.env.apiHost is https://www.noticeeverythingcreative.com/api
const meta = await ctx.$axios(<any>{
    method: 'post',
    url: `${ ctx.env.apiHost }/contact/meta`,
    headers: { 'Content-Type': 'application/json' }
});

return { meta: meta.data };
...