前端代码可在 GitHub 存储库中找到。它基于 Django 单体(https://github.com/PacktPublishing/Hands-On-Docker-for-Microservices-with-Python/tree/master/Chapter01/Monolith)在第 1 章,采取行动——设计、计划和执行。
与单体的主要区别在于不访问数据库。因此,Django ORM 没有用处。它们被对其他后端的 HTTP 请求所取代。为了发出请求,我们使用了奇妙的 requests 库。
例如,search.py 文件被转换为以下代码,它将搜索委托给 Thoughts Backend 微服务。请注意客户的请求如何转换为对 GET /api/thoughts 端点的内部 API 调用。结果以 JSON 格式解码并呈现在模板中:
import requests
def search(request):
username = get_username_from_session(request)
search_param = request.GET.get('search')
url = settings.THOUGHTS_BACKEND + '/api/thoughts/'
params = {
'search': search_param,
}
result = requests.get(url, params=params)
results = result.json()
context = {
'thoughts': results,
'username': username,
}
return render(request, 'search.html', context)
可以在 repo 的 Chapter01 子目录中比较整体等效代码 (https://github.com/PacktPublishing/Hands-On-Docker-for-Microservices-with-Python/blob/master /Chapter01/Monolith/mythoughts/thoughts/search.py)。
Note how we make a
get request through the
requests library to the defined search endpoint, which results in the
json format being returned and rendered.
THOUGTHS_BACKEND 根 URL 来自设置,采用通常的 Django 方式。
此示例很简单,因为不涉及身份验证。参数从用户界面捕获,然后路由到后端。请求在后端和获得结果后都被正确格式化,然后呈现。这是两个微服务协同工作的核心。
一个更有趣的案例是 list_thought(https://github.com/PacktPublishing/Hands-On-Docker-for-Microservices-with-Python/blob/master/Chapter06/frontend/ mythoughts/thoughts/thoughts.py#L18) 视图。以下代码列出了登录用户的想法:
def list_thoughts(request):
username = get_username_from_session(request)
if not username:
return redirect('login')
url = settings.THOUGHTS_BACKEND + '/api/me/thoughts/'
headers = {
'Authorization': request.COOKIES.get('session'),
}
result = requests.get(url, headers=headers)
if result.status_code != http.client.OK:
return redirect('login')
context = {
'thoughts': result.json(),
'username': username,
}
return render(request, 'list_thoughts.html', context)
在这里,在做任何事情之前,我们需要检查用户是否登录。这是在 get_username_from_session 调用中完成的,它返回 username 或 None
,如果他们没有登录。如果他们没有登录,返回被重定向到登录屏幕。
由于此端点需要身份验证,我们需要在 Authorization 标头中将来自用户的会话添加到我们的请求中。用户的会话可以从request.COOKIES 字典中获取。
作为保障,我们需要检查后端返回的状态码是否正确。对于此调用,任何不是 200(HTTP 调用正确)的结果状态代码都会产生到登录页面的重定向。
For simplicity and clarity, our example services are not handling different error cases. In a production system, there should be a differentiation between errors where the issue is that either the user is not logged in or there's another kind of user error (a 400 error), or the backend service is not available (a 500 status code).
Error handling, when done properly, is difficult, but worth doing well, especially if the error helps users to understand what happened.
get_username_from_session函数封装了对validate_token_header的调用,和上一章介绍的一样:
def get_username_from_session(request):
cookie_session = request.COOKIES.get('session')
username = validate_token_header(cookie_session,
settings.TOKENS_PUBLIC_KEY)
if not username:
return None
return username
settings 文件包含解码令牌所需的公钥。
在本章中,为简单起见,我们将密钥直接复制到
设置文件。这不是生产环境的方式。任何秘密都应该通过 Kubernetes 环境配置获得。我们将在接下来的章节中看到如何做到这一点。
环境文件需要指定用户后端和想法后端的基本 URL 的位置,以便能够连接到它们。