GET http://api:1337/games net :: ERR_NAME_NOT_RESOLVED для страниц nuxt.js с использованием asyncData - PullRequest
2 голосов
/ 10 марта 2019

У меня несколько сложная настройка с докером. Все работает, как и ожидалось, за исключением того, что у меня есть эта странная проблема. Посещение index страницы или / pages / _id страниц У меня нет ошибок. Но когда я пытаюсь открыть / other-page , происходит сбой. Все используют один и тот же URL API.

В консоли обнаружена ошибка при открытии / other-page :

GET http://api:1337/games net :: ERR_NAME_NOT_RESOLVED

Не знаете, что делать, есть предложения?

nuxt.config.js

  axios: {
    baseURL: 'http://api:1337'
  },

докер-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

index.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 }
  },
...

page.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 }
  },
...

Nginx conf

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

UPDATE:

Попробовал то, что предложил Томаслевейль. Теперь я получаю следующую ошибку:

nuxt | [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": ""
         }
      }
    }
  }

докер-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

1 Ответ

3 голосов
/ 10 марта 2019

Посещение страницы индекса или / pages / _id страниц У меня нет ошибок.Но когда я пытаюсь открыть / другую страницу, она вылетает.

Чтобы переформулировать:

  • У меня есть главная страница на /, которая показывает некоторые ссылки, нацеленные на страницы в/pages/_id (где _id - действительный идентификатор игры)
  • Когда я открываю / или /pages/_id, содержимое отображается
  • Но если я нажимаю ссылку со страницы / таргетинг /pages/xxx (где xxx - действительный идентификатор), я получил ошибку
  • Кроме того, если я обновляю страницу, я вижу содержимое, а не сообщение об ошибке
  • .для этих страниц приходит с сервера API.Страницы должны извлекать содержимое, вызывая сервер API, а затем отображать содержимое страницы с ответом.

Что здесь происходит?

AsyncData

Способ asyncData работает в nuxt.js следующим образом:

при загрузке первой страницы

  1. пользователь вводит URL http://yourserver/pages/123 в своем браузере
  2. веб-сервер nuxt обрабатывает запрос, разрешает маршрут и монтирует компонент vue для этой страницы
  3. метод asyncData из компонента vue вызывается со стороны сервера nuxt.js
  4. сервер nuxt.js (не пользовательский браузер) затем извлекает контент, совершая другой вызов http://api:1337/games/123, получает ответ и контент отображает.

когда пользователь нажимает на ссылку для другой страницы

Сейчас происходит что-то немного другое.

  1. Пользователь по-прежнему находится на странице http://api:1337/games/123, на которой есть ссылка на главную страницу со списком всех игр (http://yourserver/) и щелкните ее.
  2. theбраузер не загружает новую страницу .Вместо этого пользовательский браузер выполняет ajax-вызов http://api:1337/games, чтобы попытаться получить новый контент.И происходит сбой из-за ошибки разрешения имени

Почему?

Эта функция предоставлена ​​nuxt.js для ускорения загрузки контента страницы.из документации важный бит информации:

asyncData вызывается каждый раз перед загрузкой компонента страницы.Он будет вызываться на стороне сервера один раз (при первом запросе к приложению Nuxt) и на стороне клиента при переходе к следующим маршрутам.

  • server-side означает, что вызов сделан изNUXT сервер к серверу API
  • client-side означает, что вызов сделан из браузера пользователя на сервер API

Теперь самое интересное:

  • сервер nuxt работает в первом контейнере
  • сервер API работает во втором контейнере и прослушивает порт 1337
  • из контейнера nuxt, URL для вызова APIсервер http://api:1337/, и это нормально работает
  • из браузера пользователя, вызов http://api:1337 завершается неудачно (net::ERR_NAME_NOT_RESOLVED), потому что компьютер пользователя не знает, как преобразовать имя домена api в IPадрес.И даже если бы это было возможно, этот IP-адрес был бы недоступен в любом случае.

Что можно сделать?

  • Вам необходимо настроить обратный прокси-сервер, который будет пересылать запросы, сделанныебраузерами пользователей URL, начинающиеся с http://yourserver/api/ в контейнер api на порту 1337.
  • И вам нужно настроить nuxt.js так, чтобы ссылки на API делали client-side (изпользовательский браузер) используйте URL http://yourserver/api вместо http://api:1337/
  • И вам нужно настроить nuxt.js так, чтобы он продолжал вызывать http://api:1337 для вызовов server-side.

добавление обратного прокси-сервера для вызовов из nuxt (server-side)

Поскольку вы используете модуль Axios *1123* nuxt.js для выполнения вызовов в контейнер API, вы наполовину

Модуль Axios имеет опцию proxy , которую можно установить на true в nuxtjs.config.js

Ниже приведен пример настройкиобратный прокси для вашего проекта, использующий Traefik , но в документации указано, что прокси несовместимс использованием опции baseURL .Вместо этого следует использовать параметр prefix .

Ваш nuxt.config.js должен выглядеть следующим образом:

  axios: {
    prefix: '/api',
    proxy: true
  }, 
  proxy: {
    '/api/': {
      target: 'http://localhost:1337',
      pathRewrite: {
        '^/api/': ''
      }
    }
  },

Это прекрасно работает с вашего компьютера разработки, где, если strapi работает и отвечает на http://localhost:1337. Но это не сработает в контейнере, потому что нам нужно заменить http://localhost:1337 на http://api:1337. Для этого мы можем ввести переменную окружения (STRAPI_URL):

  axios: {
    prefix: '/api',
    proxy: true
  }, 
  proxy: {
    '/api/': {
      target: process.env.STRAPI_URL || 'http://localhost:1337',
      pathRewrite: {
        '^/api/': ''
      }
    }
  },

Позже мы установим STRAPI_URL в файле docker-compose.yml.

добавление обратного прокси для звонков, сделанных из браузера пользователя (client-side)

Поскольку я отказался от реализации обратных прокси с nginx при использовании docker, вот пример с Traefik :

докер-compose.yml:

version: '3'

services:
  reverseproxy:  # see https://docs.traefik.io/#the-traefik-quickstart-using-docker
    image: traefik
    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

Теперь все HTTP-запросы, сделанные браузером пользователя на http://yourserver, будут обрабатываться обратным прокси-сервером Traefik.

Traefik настроит правила пересылки, просматривая метки, начинающиеся с traefik. на контейнерах nuxt и api.

Что изменилось?

Теперь у вас есть 2 обратных прокси:

  • один для server-side запросов (прокси-модуль nuxt.js )
  • один для client-side запросов (Traefik)

Это еще не сделано

Теперь нам нужно проинструктировать прокси-модуль 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/': ''
      }
    }
  },

докер-compose.yml

version: '3'

services:
  reverseproxy:  # see https://docs.traefik.io/#the-traefik-quickstart-using-docker
    image: traefik
    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

...