Я создаю простой веб-сайт с логином, и мой vue-интерфейс должен получать пользовательские данные из моего nodejs-backend, который подключается к базе данных sql. Я решил использовать для этого docker-compose, и как я понимаю, docker-compose автоматически настраивает сеть для сервисов, которые упомянуты в моем docker-compose.yml.
Что не работает, так это то, как я обращаюсь к серверной части в своем коде. Я подозреваю, что это может быть из-за того, как я использую axios для отправки запроса на мой сервер.
Я проверил сеть докеров по умолчанию и смог пропинговать от моего внешнего интерфейса к моему внутреннему, используя имена DNS, которые я нашел в конфигурации сети. Но использование тех же имен внутри моего кода не сработало.
Что действительно работает, так это сопоставление порта хоста с моим открытым портом API и использование http://локальный: 5000 в качестве адреса, но это противоречит цели сети докеров.
мой докер-compose.yml:
version: '3.3'
services:
vue-frontend:
image: flowmotion/vue-js-frontend
ports:
- 8070:80
depends_on:
- db-user-api
db-user-api:
image: flowmotion/user-db-api
environment:
- PORT=5000
ports:
- 5000:5000 #only needed if docker network connection can't be established
рассматриваемые файлы Vue-fontend:
Логин.vue
methods: {
async login() {
try {
const response = await authenticationService.login({
email: this.email,
password: this.password
});
this.$store.dispatch("setToken", response.data.token);
this.$store.dispatch("setUser", response.data.user);
this.$router.push({ path: "/" });
} catch (error) {
this.showError = true;
this.error = error.response.data.error;
}
}
}
};
</script>
аутентификацияService.js
import api from "@/services/api";
export default {
login(credentials) {
return api().post("login", credentials);
}
};
API.js
import axios from 'axios';
import config from '../config/config';
export default () => {
return axios.create({
baseURL: config.userBackendServer
});
};
конфиг.js ()
module.exports = {
userBackendServer: 'http://cl-dashboard_db-user-api_1:5000' //this doesn't seem to work
};
//using 'http://localhost:5000' works if ports are mapped to host machine.
ожидаемым результатом будет мой бэкэнд, выполняющий поиск sql.
фактический результат: вместо того, чтобы подключаться к моему бэкэнду, мой интерфейс дает мне статус 404, и мой бэкэнд никогда не доступен
вы правы, предполагая, что контейнеры в сети докеров могут общаться друг с другом, не открывая никаких портов во внешний мир.
точка - ваше приложение vue не находится ни в одном контейнере - оно подается из контейнера в виде файла сценария js в ваш браузер., которая отправляет запросы на серверную часть вашего узла. поскольку ваш браузер никоим образом не находится внутри сети докеров - вы должны использовать внешнее сопоставление портов (localhost:5000
в вашем случае), чтобы получить доступ к серверной части.
дайте мне знать, если у вас есть еще вопросы по этому поводу.
поместите его как переменную среды в свой файл .env
в корневой каталог приложения vue. на данный момент это будет VUE_APP_API_ROOT=http://localhost:500/
, и на производстве измените его на имя хоста вашего сервера. предполагается, что ваш серверный производственный контейнер будет сопоставлен с портами хоста по умолчанию (80 и 443), и поэтому вам не нужно указывать какой-либо номер порта.
Как насчет привязки портов не к хост-компьютеру, а к данной сети? Например, чтобы избежать прямого доступа к портам служб хосту, я настроил свои контейнеры на использование интерфейса Docker. Теперь я не могу подключить свои сервера к себе. Есть идеи?
@GustavoSilva, не могли бы вы рассказать мне больше о том, как выполняется эта «привязка к заданной сети»? Я не уверен, что получил тебя. если это на github, вы можете связать это здесь, и я посмотрю
@EfratLevitan, этого нет на GitHub. У меня есть установка, аналогичная описанной выше. Разница в том, что я использую IP-адрес сетевого интерфейса Docker вместо прямой привязки портов служб к хосту. Таким образом, мой порт имеет конфигурацию, аналогичную: порт: - 172.17.0.1:3000:5000
по какому адресу вы получаете доступ к контейнеру из своего браузера? это тот адрес, который должен быть передан интерфейсу как VUE_APP_API_ROOT
.
У меня было что-то подобное, да. Я не так легко получаю доступ к контейнерам снаружи. Конфигурация nginx моего хоста соответственно реверсирует прокси. Помните, что я открываю только порты контейнеров для сети докеров.
@GustavoSilva, если контейнер недоступен за пределами сети докеров, внешнее приложение не сможет отправлять запросы
В этом есть смысл. Я надеялся, что контейнеры смогут общаться друг с другом, если они все находятся в одной сети, независимо от того, какие сетевые драйверы они используют (br0, dckr0 или что-то еще).
@GustavoSilva есть, но внешнее приложение не находится внутри контейнера - оно запускается из браузера. (обратитесь к моему ответу)
Да, я следую. Я думаю, мне нужно снова посмотреть на структуру и проверить, что можно сделать. Спасибо за вашу помощь! :+1:
@EfratLevitan, как новичок в веб-приложениях, я этого не понимаю: я бы предположил, что передний контейнер является передним для клиента. Таким образом, любой запрос к этому фронту будет делать что-то внутри, что неизвестно пользователю - обращаться к заднему контейнеру и получать ответ. Но здесь происходит то, что пользователь действительно видит, что делает фронт, и может сделать это сам. 1. Это нормально? Разве не уродливо использовать два адреса для одного сайта? 2. Разве для этого сценария не требуется CORS (developer.mozilla.org/en-US/docs/Web/HTTP/CORS), который является хаком? Спасибо!
@hudac 1. внешние приложения работают на стороне клиента, и да, он может просматривать их и манипулировать ими столько, сколько захочет, поэтому любое конфиденциальное действие (например, обращение к БД) должно выполняться с внутренней стороны, а не со стороны клиент. 2. вы можете использовать dev-прокси, чтобы избежать проблем с CORS, вот как это сделать: medium.com/js-dojo/…
@EfratLevitan Я не говорю о разработке, я говорю о производстве. Правильно ли работают веб-приложения? например Я захожу на myapp.com, и каждый щелчок, требующий доступа к базе данных (а не только изменения внешнего интерфейса js), скрытно переходит на myapp.back.com? Это правильный способ сделать это? Я думал, что CORS предназначен только для внешнего (не адреса myapp.com) контента.
@hudac Правильно, заголовки CORS не должны использоваться в производстве. Обычная архитектура помещает прокси-сервер (скажем, nginx), который обслуживает внешний файл, и перенаправляет /api/*
запросы на внутренний сервер. пример: cli.vuejs.org/guide/deployment.html#docker-nginx
@EfratLevitan, да, я читал об этом. Единственное, чего я не понимаю в этом методе, это: 1. конкретно в приложенном вами примере я думаю, что не вижу другого маршрута, кроме root '/'. 2. Если есть другой маршрут - nginx его прямо туда пропускает? или он проходит через мой js-код? Я имею в виду - скажем, у меня есть код, который идет в базу данных, и для каждой записи, которую он получает, он выполняет некоторые манипуляции, а затем красиво показывает это в графическом интерфейсе. Если nginx направит мой запрос не через мой код js, разве я не получу необработанные данные?
Кстати, возможно, этот пример не отражает вариант использования, который я пытаюсь изобразить. В вашей ссылке написано: «Если вы используете Vue CLI вместе с серверной структурой, которая обрабатывает статические ресурсы как часть своего развертывания». Я думаю, что мой вариант использования - db. не статические активы.
хорошо, я нашел этот пример github.com/wkrzywiec/kanban-board/blob/master/kanban-ui/… - обратный прокси-сервер nginx, который перенаправляет внутренние вызовы для /api/*. Спасибо!
Здравствуйте, это старый вопрос, и я столкнулся с той же проблемой. Я понял, о чем идет речь, и я попробую в ближайшее время. Мой вопрос к @EfratLevitan, в какой-то момент вы упомянули: and on production change it to your server hostname
. Как это сделать, в том смысле, что вам нужно будет знать свой производственный URL-адрес во время сборки, поскольку после этого вы не можете изменить переменную. Я прав? Или с Vue вы можете сделать это? Поскольку я использую реакцию, я знаю, что после ее создания я не могу изменить это значение.
@Vivere В производственной среде вы обычно устанавливаете прокси-сервер для получения одного и того же доменного имени для внешнего интерфейса и внутреннего интерфейса (в противном случае вы сталкиваетесь с CORS), поэтому вы можете исключить имя хоста из запрошенного URL-адреса, и по умолчанию браузер будет использовать доменное имя внешнего интерфейса в качестве имени хоста ( например, вы отправляете AJAX на «/api/image1.png») без имени хоста.
хорошо, это имеет смысл. Итак, для развертывания мне нужно указать обслуживающий IP-адрес/URI с портом, указанным в моем docker-compose.yml? вот так: userBackendServer: 'URItoMyApp:5000'