【问题标题】:Nuxt.js SSR w/ Nest API deployed to AWS in a Docker containerNuxt.js SSR w/ Nest API 在 Docker 容器中部署到 AWS
【发布时间】:2020-05-19 16:22:48
【问题描述】:

我在这里尝试了大约 500 万个主题变体,并且花了很多时间研究 Nuxt 文档,但当部署到 AWS 的 docker 容器中时,我无法使用 Nest 后端工作的 Nuxt SSR。下面是我目前的设置。如果我遗漏了什么,请告诉我。

这是我遇到的错误:

https://www.noticeeverythingcreative.com/contact 该路由在组件的asyncData 方法中向https://www.noticeeverythingcreative.com/api/contact/meta 发出POST 页面元请求。这会从 Axios 产生一个很大的旧错误。以下是我认为相关的部分,但如果您需要更多,请告诉我。

{
  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 存储库。然后我通过 SSH 连接到我的服务器并使用此撰写文件运行 docker-compose up -d

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.');
        }
    }
}

这是客户端联系人组件的asyncDatahead 实现:

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 &amp;&amp; cross-env NODE_ENV=development node .nuxt/api/index.js 并且应用程序运行和呈现没有错误。

更新

如果我允许 Nuxt 应用程序在 docker 容器内的 localhost 上实际运行,我最终会遇到相反的问题。例如,如果我将 nuxt.config.js 服务器和 axios 块更改为

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 };

https://www.noticeeverythingcreative.com/contact 的新负载渲染良好。这可以通过查看页面源并查看标题已更新并且没有控制台错误来确认。但是,如果您加载主页 (https://www.noticeeverythingcreative.com) 并单击导航中的联系人链接,您将看到 POST http://localhost:3002/api/contact/meta net::ERR_CONNECTION_REFUSED

注意:这是在上次编辑此问题时部署的版本。

【问题讨论】:

  • 刚测试,报错:> 报错:ENOENT:没有这样的文件或目录,根据报错打开'/app/.nuxt/server/app/email/img/gh.png'嵌套控制器路径匹配可能不正确,并且请求正在尝试从 nuxt 应用程序而不是 Nest API 端点加载内容。 noticeeverythingcreative.com/api 呈现 Nuxt 错误页面而不是 404 或预期的 API 错误这一事实似乎验证了这一想法。你能分享一下你拥有的控制器规则的细节吗?
  • 抱歉,我应该更清楚地知道表单提交不是问题。只是页面的呈现,特别是对 /api/contact/meta 的 POST 请求。除了上面 sn-p 中 NuxtController 中的请求之外,没有任何 GET 请求的服务器端处理程序。
  • 换句话说,我很确定这是一个网络问题,而不是逻辑问题。抱歉,如果不清楚。
  • 我明白了 - 你能分享一下 sn-p 调用表格进行比较和对比吗?我尝试做的一件事是使 axios 请求中的所有 URL 都是相对的,而不是预先添加 apiHost,因为您正在调用与源相同的主机。
  • 表单提交调用是相同的,除了表单数据和端点。它绝对有效。我刚刚部署了错误的图像路径修复程序。我实际上看到了您从 test@test.com 退回的电子邮件。我实际上已经尝试过相对路径,但失败了,因为即使正确设置了 Axios baseURL,它仍然会将请求发送到 localhost:3002

标签: docker axios nuxt.js nestjs


【解决方案1】:

我想出了一个解决方案,但我不喜欢它,所以如果有人有更好的解决方案,请发布。

我通过允许 Nuxt 应用程序在 docker 容器内的 localhost 上运行,但向实际主机发出 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 之外的任何内容,以及 nuxt 所依赖的任何 env 变量(主要是因为我不太清楚这些在 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 };

【讨论】:

    猜你喜欢
    • 2019-09-20
    • 2020-12-04
    • 2021-06-24
    • 1970-01-01
    • 2020-11-22
    • 2018-04-13
    • 2021-07-19
    • 2018-02-05
    • 2020-09-10
    相关资源
    最近更新 更多