Я уже прочитал множество тем об этом, но до сих пор не нашел лучшего подхода.
У меня User
. Один User
может иметь много Posts
. Пользователи и сообщения - это микросервисы другой. Я использую Spring Boot.
Когда интерфейс вызывает мою микросервис Posts
, отправляя запрос POST
в /posts/user/1
, мне нужно проверить, существует ли данный userId
(1) в моей базе данных Users
. Если нет, генерировать исключение, сообщающее клиентской части, что пользователь не существует. Если да, то вставьте данное тело запроса как Post
.
Возникает вопрос: как мне проверить эту информацию на моем сервере? Мы не хотим перекладывать эту ответственность на внешний интерфейс, поскольку javascript является клиентским, и злоумышленник может обойти эту проверку.
Параметры:
Я понимаю, что общение между ними создаст связь, но я не уверен, что предоставление доступа Post к базе данных пользователей является лучшим вариантом.
Не стесняйтесь предлагать любые варианты.
У вас есть возможность осуществлять межпроцессное взаимодействие между микросервисами Post
и User
с помощью подхода RESTful
.
В случае, если вы просто хотите проверить наличие ресурса и не хотите, чтобы в ответ было какое-либо тело, вам следует использовать HTTP-метод HEAD
. Поэтому ваша конечная точка API, размещенная на микросервисе User
, будет выглядеть так:
HEAD user/{userId}
Вызовите этот API из микросервиса Post
.
Return 200 / OK if user exist
Return 404 / Not Found if user does not exist
кликните сюда и здесь, чтобы получить более подробную информацию об использовании метода HEAD
и вариантах использования.
Вы правы, вы должны выполнить проверку на бэкэнде, поскольку, я полагаю, это служба REST, и запросы можно отправлять не только из пользовательского интерфейса.
Предположим, у вас есть реализация сервиса:
@Service
class UsersServiceImpl implements UsersService {
private final Users users;
public UsersServiceImpl(Users users) {
this.users = users;
}
@Override
public void addPost(long userId, Post post) {
User user = users.get(userId);
if (user == null) {
throw new UserNonExistent(userId);
}
user.addPost(post);
}
}
где Users
- это интерфейс, представляющий базу данных пользователей, а UserNonExistent
- это RuntimeException. Затем в вашем контроллере вы можете сделать следующее:
@RestController
class UsersController {
private final UsersService usersService;
public UsersController(UsersService usersService) {
this.usersService = usersService;
}
@PostMapping("/posts/user/{userId}")
public void addPostToUser(@PathVariable String userId, @RequestBody Post post) {
usersService.addPost(userId, post);
}
@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "User does not exist")
@ExceptionHandler({UsersService.UserNonExistent.class})
public void handleUserNonExistentException() {
// Nothing to do
}
}
Если предоставленный ID пользователя недействителен, будет вызван метод handleUserNonExistentException()
, который вернет код состояния HTTP ПЛОХОЙ ЗАПРОС.
Этот ответ предполагает, что сервер является монолитом, тогда как OP четко заявил, что вопрос касается микросервисов.
Для этого очень конкретного случая использования, если у вас есть уровень безопасности, вы можете (должны) использовать токен доступа пользователя, чтобы гарантировать, что этот запрос обрабатывается для правильного пользователя, что может быть выполнено путем проверки токена и полагаясь на факт, что если у пользователя есть токен, он существует. (Поскольку дело не в том, существует ли пользователь)
Для любой другой логики, скажем, вы хотите проверить, разрешено ли ему публиковать или другие подобные ограничения, необходимо сделать вызов пользовательской службе.
Говоря о предоставлении доступа к базе данных, это будет противоречить одному из основных правил микросервисов. Это создаст тесную связь между вами и пользователем. В этом случае можно вызвать в службу пользователя, которая может решить, как обслужить этот запрос. Пользовательский сервис со своей стороны должен предоставлять способы ответа на ваши запросы в рамках SLA с помощью кэширования или других механизмов.
Еще одна вещь, которую вы можете изучить, - это Лучшая подруга (Backend для Frontend). Вы правильно сказали, что не должны открывать серверные службы для внешнего интерфейса или добавлять туда какую-либо логику, но часто интерфейсным страницам может быть неудобно принимать, что контент на той же странице отвечает через n разных серверных служб, и может быть некоторая логика для сшивания таких запросов и вот где вы можете использовать BFF. Бэкэнд-сервер (в моем случае node), который берет на себя такие вещи, как эти, требующие, чтобы интерфейс выполнял только один вызов (или меньше вызовов) для данной страницы и в то же время скрывает ваши внутренние службы внутри.
Данные важны и должны быть защищены. Так что, на мой взгляд, нормально иметь службу, которая находится в верхней части вашего бэкэнда (база данных в вашем случае), и вы открываете общедоступные конечные точки, используя правильную аутентификацию и контроль доступа.