使用 asyncData 为 nuxt.js 页面获取 http://api:1337/games net::ERR_NAME_NOT_RESOLVED

emi*_*ski 6 docker strapi traefik nuxt.js

我对 docker 的设置有些复杂。一切都按预期工作,除了我有这个奇怪的问题。访问索引页或/pages/_id页我没有错误。但是当我尝试打开/other-page 时它崩溃了。所有人都使用相同的 API url。

打开/other-page时在控制台中发现错误:

获取http://api:1337/games net::ERR_NAME_NOT_RESOLVED

不知道该怎么办,有什么建议吗?

nuxt.config.js

  axios: {
    baseURL: 'http://api:1337'
  },
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml

version: '3'

services:
  api:
    build: .
    image: strapi/strapi
    environment:
      - APP_NAME=strapi-app
      - DATABASE_CLIENT=mongo
      - DATABASE_HOST=db
      - DATABASE_PORT=27017
      - DATABASE_NAME=strapi
      - DATABASE_USERNAME=
      - DATABASE_PASSWORD=
      - DATABASE_SSL=false
      - DATABASE_AUTHENTICATION_DATABASE=strapi
      - HOST=api
      - NODE_ENV=production
    ports:
      - 1337:1337
    volumes:
      - ./strapi-app:/usr/src/api/strapi-app
      #- /usr/src/api/strapi-app/node_modules
    depends_on:
      - db
    restart: always
    links:
      - db

  nuxt:
    # build: ./app/
    image: "registry.gitlab.com/username/package:latest"
    container_name: nuxt
    restart: always
    ports:
      - "3000:3000"
    links:
      - api:api
    command:
      "npm run start"


  nginx:
    image: nginx:1.14.2
    expose:
      - 80
    container_name: nginx
    restart: always
    ports:
      - "80:80"
    volumes:
      - ./nginx:/etc/nginx/conf.d
    depends_on:
      - nuxt
    links:
      - nuxt
Run Code Online (Sandbox Code Playgroud)

索引.vue

...
  async asyncData({ store, $axios }) {
    const games = await $axios.$get('/games')
    store.commit('games/emptyList')
    games.forEach(game => {
      store.commit('games/add', {
        id: game.id || game._id,
        ...game
      })
    })
    return { games }
  },
...
Run Code Online (Sandbox Code Playgroud)

页面.vue

...
  async asyncData({ store, $axios }) {
    const games = await $axios.$get('/games')
    store.commit('games/emptyList')
    games.forEach(game => {
      store.commit('games/add', {
        id: game.id || game._id,
        ...game
      })
    })
    return { games }
  },
...
Run Code Online (Sandbox Code Playgroud)

Nginx 配置文件

upstream webserver {
  ip_hash;
  server nuxt:3000;
}

server {
  listen 80;
  access_log off;
  connection_pool_size 512k;
  large_client_header_buffers 4 512k;

  location / {
    proxy_pass http://webserver;
    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;
    proxy_max_temp_file_size 0;
  }
Run Code Online (Sandbox Code Playgroud)

更新:

尝试了 Thomasleveil 的建议。现在我收到以下错误:

纽斯特 | [2:09:35 PM] 错误:连接 ECONNREFUSED 127.0.0.1:80

所以,现在似乎 /api 被转发到 127.0.0.1:80。不知道为什么^^

nuxt.config.js

  axios: {
    baseURL: '/api'
  },
  server: {
    proxyTable: {
      '/api': {
         target: 'http://localhost:1337',
         changeOrigin: true,
         pathRewrite: {
           "^/api": ""
         }
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml

version: '3'

services:
  reverse-proxy:
    image: traefik # The official Traefik docker image
    command: --api --docker # Enables the web UI and tells Traefik to listen to docker
    ports:
      - "80:80"     # The HTTP port
      - "8080:8080" # The Web UI (enabled by --api)
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock # listen to the Docker events
    networks:
      - mynet

  api:
    build: .
    image: strapi/strapi
    container_name: api
    environment:
      - APP_NAME=strapi-app
      - DATABASE_CLIENT=mongo
      - DATABASE_HOST=db
      - DATABASE_PORT=27017
      - DATABASE_NAME=strapi
      - DATABASE_USERNAME=
      - DATABASE_PASSWORD=
      - DATABASE_SSL=false
      - DATABASE_AUTHENTICATION_DATABASE=strapi
      - HOST=api
      - NODE_ENV=development
    ports:
      - 1337:1337
    volumes:
      - ./strapi-app:/usr/src/api/strapi-app
      #- /usr/src/api/strapi-app/node_modules
    depends_on:
      - db
    restart: always
    networks:
      - mynet
    labels:
      - "traefik.backend=api"
      - "traefik.docker.network=mynet"
      - "traefik.frontend.rule=Host:example.com;PathPrefixStrip:/api"
      - "traefik.port=1337"

  db:
    image: mongo
    environment:
      - MONGO_INITDB_DATABASE=strapi
    ports:
      - 27017:27017
    volumes:
      - ./db:/data/db
    restart: always
    networks:
      - mynet

  nuxt:
    # build: ./app/
    image: "registry.gitlab.com/username/package:latest"
    container_name: nuxt
    restart: always
    ports:
      - "3000:3000"
    command:
      "npm run start"
    networks:
      - mynet
    labels:
      - "traefik.backend=nuxt"
      - "traefik.frontend.rule=Host:example.com;PathPrefixStrip:/"
      - "traefik.docker.network=web"
      - "traefik.port=3000"

networks:
  mynet:
    external: true
Run Code Online (Sandbox Code Playgroud)

Tho*_*eil 11

访问索引页或 /pages/_id 页我没有错误。但是当我尝试打开 /other-page 时它崩溃了。

重新制定:

  • 我有一个主页/,显示了一些指向页面的链接/pages/_id_id有效的游戏 ID在哪里)
  • 当我打开/或 时/pages/_id,内容显示
  • 但是,如果我单击页面/定位中的链接/pages/xxxxxx有效 ID在哪里),则会出现错误
  • 此外,如果我刷新页面,我就会看到内容而不是错误
  • 这些页面的内容来自 api 服务器。页面应该通过调用 api 服务器来获取内容,然后使用响应呈现页面内容。

这里发生了什么事?

异步数据

asyncData在 nuxt.js 中的工作方式如下:

在第一页加载时

  1. 用户http://yourserver/pages/123在其浏览器中输入网址
  2. nuxt Web 服务器处理请求,解析路由并为该页面挂载 vue 组件
  3. asyncDatavue组件的方法是从nuxt.js服务端调用的
  4. 然后 nuxt.js 服务器(不是用户浏览器)通过对 进行不同的调用来获取内容http://api:1337/games/123,接收响应并呈现内容。

当用户点击另一个页面的链接时

现在发生了一些不同的事情。

  1. 用户仍然在http://api:1337/games/123有一个链接到列出所有游戏的主页的页面上 ( http://yourserver/) 并单击它。
  2. 浏览器不会加载任何新页面。相反,用户浏览器会调用 ajaxhttp://api:1337/games来尝试获取新内容。并且由于名称解析错误而失败

为什么?

这是 nuxt.js 为您带来的一项功能,用于加快页面内容加载时间。从文档中,重要的信息是:

asyncData每次加载页面组件之前都会调用。它将在服务器端调用一次(在对 Nuxt 应用程序的第一个请求时)和客户端在导航到更多路由时调用。

  • server-side 表示调用是从 nuxt 服务器到 api 服务器
  • client-side 表示调用是从用户浏览器到 api 服务器

现在有趣的部分:

  • nuxt 服务器在第一个容器中运行
  • api 服务器在第二个容器中运行并正在侦听端口 1337
  • 从nuxt容器,调用api服务器的url是http://api:1337/,这工作正常
  • 从用户浏览器调用http://api:1337失败 ( net::ERR_NAME_NOT_RESOLVED),因为用户计算机不知道如何将域名api转换为 IP 地址。即使可以,这个 IP 地址也将无法访问。

可以做什么?

  • 您需要设置一个反向代理,它将用户浏览器发出的请求转发到 url 开始http://yourserver/api/apiport上的容器1337
  • 并且您需要配置 nuxt.js 以便client-side(从用户浏览器)创建的 api 链接使用 urlhttp://yourserver/api而不是http://api:1337/
  • 并且您需要配置 nuxt.js 以便它不断调用http://api:1337调用 made server-side

为来自 nuxt ( server-side) 的调用添加反向代理

由于您正在使用nuxt.js Axios 模块来调用 api 容器,因此您已经完成了一半。

Axios 模块有一个代理选项,可以true在 nuxtjs.config.js 中设置

Bellow 是使用Traefik为您的项目设置反向代理的示例,但文档指出该代理与baseURL选项的使用不兼容。该前缀选项必须被使用。

你的 nuxt.config.js 应该是这样的:

  axios: {
    prefix: '/api',
    proxy: true
  }, 
  proxy: {
    '/api/': {
      target: 'http://localhost:1337',
      pathRewrite: {
        '^/api/': ''
      }
    }
  },
Run Code Online (Sandbox Code Playgroud)

这在您的开发计算机上运行良好,如果 Strapi 正在运行并以http://localhost:1337. 但这在容器中不起作用,因为我们需要替换http://localhost:1337http://api:1337. 为此,我们可以引入一个环境变量 ( STRAPI_URL):

  axios: {
    prefix: '/api',
    proxy: true
  }, 
  proxy: {
    '/api/': {
      target: process.env.STRAPI_URL || 'http://localhost:1337',
      pathRewrite: {
        '^/api/': ''
      }
    }
  },
Run Code Online (Sandbox Code Playgroud)

我们稍后将STRAPI_URL在 docker-compose.yml 文件中设置 。

为来自用户浏览器的调用添加反向代理 ( client-side)

由于我在使用docker时放弃了使用 nginx 实现反向代理,这里有一个Traefik的例子:

docker-compose.yml:

version: '3'

services:
  reverseproxy:  # see https://docs.traefik.io/#the-traefik-quickstart-using-docker
    image: traefik:1.7
    command: --docker
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  api:
    image: strapi/strapi
    environment:
      - ...
    expose:
      - 1337
    labels:
      traefik.frontend.rule: PathPrefixStrip:/api
      traefik.port: 1337

  nuxt:
    image: ...
    expose:
      - 3000
    command:
      "npm run start"
    labels:
      traefik.frontend.rule: PathPrefixStrip:/
      traefik.port: 3000

Run Code Online (Sandbox Code Playgroud)

现在,用户浏览器发出的所有 HTTP 请求都将由http://yourserverTraefik 反向代理处理。

Traefik将通过查看标签开始配置转发规则traefik.nuxtapi容器。

发生了什么变化?

您现在有 2 个反向代理:

还没有完成

我们现在需要指示nuxt.js 代理模块它必须将请求转发到http://api:1337/. 我们将为此使用STRAPI_URL环境变量。

并且我们需要指示nuxt Axios 模块用户浏览器必须在 上调用 api http://yourserver/api。这是通过API_URL_BROWSER环境变量完成的。


全部一起

nuxt.config.js

  axios: {
    prefix: '/api',
    proxy: true
  }, 
  proxy: {
    '/api/': {
      target: process.env.STRAPI_URL || 'http://localhost:1337',
      pathRewrite: {
        '^/api/': ''
      }
    }
  },
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml

version: '3'

services:
  reverseproxy:  # see https://docs.traefik.io/#the-traefik-quickstart-using-docker
    image: traefik:1.7
    command: --docker
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  api:
    image: strapi/strapi
    environment:
      - ...
    expose:
      - 1337
    labels:
      traefik.frontend.rule: PathPrefixStrip:/api
      traefik.port: 1337

  nuxt:
    image: ...
    expose:
      - 3000
    command:
      "npm run start"
    environment:
      NUXT_HOST: 0.0.0.0
      STRAPI_URL: http://api:1337/
      API_URL_BROWSER: /api
    labels:
      traefik.frontend.rule: PathPrefixStrip:/
      traefik.port: 3000

Run Code Online (Sandbox Code Playgroud)