20、构建仪表板与Python项目打包运行

构建仪表板与Python项目打包运行

1. 微前端架构概述

在前端架构领域,微前端是一个新兴趋势。当我们使用Web前端对用户进行身份验证时,就会面临将对应代码放置何处的问题。微前端架构将前端拆分为小型、自包含的用户界面组件,这些组件可集成到更大的网站中。

以购物网站为例,首页通常包含以下几个不同部分:
- 购物类别
- 全站新闻和活动,如下期促销信息
- 突出展示和推广的商品,包括定制推荐
- 最近浏览商品列表
- 用于登录或注册账户的小部件以及其他管理工具

如果开发一个单一网页来处理所有这些元素,页面会迅速变得庞大而复杂,尤其是在不同页面需要重复使用某些元素时。许多网站通过分离 <div> 标签并将代码存于不同的JavaScript文件来区分不同功能,不过这些文件在加载到网页时可能已被编译和压缩。

这种方法会带来类似单体后端架构的问题。对后端或其用户界面的任何更改都意味着要更新微服务及其查询的用户界面元素,而这些可能位于不同的源代码控制仓库或由不同团队管理。可能需要同时支持新旧两种方式以进行管理迁移,或者需要精心安排不同的部署机制。

采用微前端架构,这些用户界面功能可由不同团队和服务负责。例如,如果“推荐”功能突然需要新的后端或不同的JavaScript框架,这是可行的,因为主网站只将其视为一个自包含的功能。任何更改也可以是自包含的,因为推荐引擎的微前端用户界面组件将位于同一仓库并由同一服务提供。只要包含微前端组件的技术不变,主用户界面就无需更改,更改可完全通过其依赖的微服务进行控制。

这也使每个组件的开发人员能够按自己的计划发布新功能和修复漏洞,而无需进行大规模的跨团队协调来在多个区域部署更新功能。团队只需确保其用户界面以一致的方式集成,接受相同的数据(如客户标识符),并返回所需大小的用户界面元素。

以Packt网站为例,加载主页时,我们会看到顶部的横幅包含常见选项,下方的横幅用于展示当前促销和活动,然后是最近新增库存的列表。如果设计这个页面,我们可以构建至少三个不同的微前端:处理会话和登录的身份验证组件、能显示并响应即将到来的会议和促销活动的事件组件,以及能显示当前库存的库存组件。不过,这种方法并非适用于所有情况,很多时候,用户界面需要与其他元素紧密交互,或者组织内的知识传播不允许以这种方式创建许多小的用户界面组件。

此外,这种架构不需要很多不同的URL。可以配置相同的nginx负载均衡器将不同的URL路由到不同的后端服务,而客户端对此毫无察觉,这为迁移到这种架构提供了一种有用的方法,因为它降低了更新端点URL的可能性。

由于微前端模型相对较新,许多最佳实践甚至一些术语仍在不断变化。因此,我们将专注于这种方法的一种更简单变体,让身份验证服务提供自己的HTML用于用户登录和创建账户,如果需要,这些HTML可以包含在另一个页面的iframe中。

2. 获取Slack令牌

Slack提供了典型的三方OAuth2实现,使用一组简单的HTTP GET请求。实现交换的方法是将用户重定向到Slack,并暴露一个端点,用户获得访问权限后浏览器会重定向到该端点。

如果我们请求特殊的“identify”范围,那么从Slack获得的只是用户身份的确认和唯一的Slack ID字符串。我们可以将所有这些信息存储在Quart会话中,将其用作登录机制,并在需要时将电子邮件和令牌值传递给DataService以供其他组件使用。

以下是生成将用户发送到Slack的URL的函数实现:

@login.route("/login/slack")
async def slack_login():
    query = {
        "client_id": current_app.config["JEEVES_CLIENT_ID"],
        "scope": "identify",
        "redirect_uri": current_app.config["SLACK_REDIRECT_URI"],
    }
    url = f"https://slack.com/oauth/authorize?{urlencode(query)}"
    return redirect(url)

这里,我们在nginx后运行Quart应用程序,并使用Let’s Encrypt证书,因此使用配置中的回调URL而不是动态计算,因为该URL与nginx相关。

该函数使用在Slack中生成的Jeeves应用程序的 client_id ,并返回一个重定向URL,我们可以将其展示给用户。仪表板视图可以相应地更改,以将该URL传递给模板。

@login.route("/")
async def index():
    return await render_template("index.html", user=session.get("user"))

我们还会传递一个 user 变量(如果会话中存储了任何用户信息)。模板可以使用该URL显示登录/注销链接,如下所示:

{% if not user %}
<a href="{{url_for('login.slack_login')}}">Login via Slack</a>
{% else %}
Hi {{user}}!
<a href="/logout">Logout</a>
{% endif %}

当用户点击登录链接时,他们会被重定向到Slack,然后返回到我们应用程序中定义为 SLACK_REDIRECT_URI 的端点。该视图的实现如下:

@login.route("/slack/callback")
async def slack_callback():
    query = {
        "code": request.args.get("code"),
        "client_id": current_app.config["JEEVES_CLIENT_ID"],
        "client_secret": current_app.config["JEEVES_CLIENT_SECRET"],
        "redirect_uri": current_app.config["SLACK_REDIRECT_URI"],
    }
    url = "https://slack.com/api/oauth.access"
    response = requests.get(url, params=query)
    response_data = response.json()
    session["user"] = response_data["user_id"]
    return redirect(url_for("login.index"))

使用从Slack的OAuth2服务获得的响应,我们将收到的临时代码放入查询中,将其转换为真正的访问令牌。然后,我们可以将令牌存储在会话中或将其发送到数据服务。

3. JavaScript身份验证

当仪表板应用程序与Slack执行OAuth2交换时,它会将用户信息存储在会话中,这对于在仪表板上进行身份验证的用户来说是一种不错的方法。然而,当ReactJS用户界面调用DataService微服务来显示用户运行数据时,我们需要提供一个身份验证头。有两种方法可以处理这个问题:
- 通过仪表板Web应用程序使用现有会话信息代理所有对微服务的调用。
- 为最终用户生成JWT令牌,该令牌可存储并用于与其他微服务交互。

代理解决方案似乎最简单,因为它无需为每个用户生成访问DataService的令牌。但这意味着如果要将事务追溯到单个用户,就必须将DataService事件与前端的事件列表关联起来。

代理允许我们将DataService隐藏起来,不让公众看到。将所有内容隐藏在仪表板后面意味着我们在更改内部结构时具有更大的灵活性,同时保持用户界面的兼容性。但问题是,即使不需要,我们也会强制所有流量通过仪表板服务。对最终用户来说,我们暴露的API和仪表板似乎有不同的数据访问路径,这可能会导致混淆。而且,如果DataService出现故障,仪表板也会受到影响,可能无法响应试图查看页面的用户。如果JavaScript直接与DataService通信,仪表板将继续运行,并可以发出通知让用户知道存在问题。

因此,我们更倾向于第二种解决方案,即为最终用户生成用于React前端的令牌。如果我们已经在向其他微服务分发令牌,那么Web用户界面只是其中一个客户端。但这也意味着客户端有第二个身份验证循环,因为它必须先使用OAuth2进行身份验证,然后获取用于内部服务的JWT令牌。

我们可以在身份验证后生成JWT令牌,然后使用它与我们控制的其他服务进行通信,工作流程与之前相同,只是从JavaScript调用而已。

4. Python项目打包相关概念

在Python编程早期,运行Python应用程序是将Python脚本指向解释器。与Python项目的打包、发布和分发相关的一切都是手动完成的,当时没有真正的标准,每个项目都有一个长长的README文件,说明如何安装及其所有依赖项。

大型项目使用系统打包工具来发布其工作,如Debian包、Red Hat Linux发行版的RPM包或Windows下的MSI包。最终,这些项目的Python模块都会被安装到Python安装目录的 site-packages 目录中,如果有C扩展,可能还需要经过编译阶段。

自1998年Distutils被添加到标准库以支持创建可安装的Python项目分发版以来,Python打包生态系统发生了很大变化。社区涌现出许多新工具,以改进Python项目的打包、发布和分发方式。

在打包方面,有几个术语容易混淆,以下是一些定义:
- Python包 :是一个包含Python模块的目录树,可以导入它,它是模块命名空间的一部分。
- Python项目 :可以包含多个包、模块和其他资源,是我们要发布的内容。使用Flask构建的每个微服务都是一个Python项目。
- Python应用程序 :是一个可以通过用户界面直接使用的Python项目,用户界面可以是命令行脚本或Web服务器。
- Python库 :是一种特殊的Python项目,它为其他Python项目提供功能,没有直接的最终用户界面。

应用程序和库之间的区别可能比较模糊,因为一些库有时会提供一些命令行工具来使用其部分功能,即使其主要用途是为其他项目提供Python包。而且,有时一个原本是库的项目可能会变成一个应用程序。

5. Python打包工具链的发展

Python的打包方式已经有了很大的进步。为了改进Python项目的安装、发布和分发方式,人们编写了许多Python增强提案(PEPs)。

Distutils存在一些缺陷,使得发布软件变得有些繁琐。最大的痛点是它缺乏依赖管理,以及处理编译和二进制发布的方式。在90年代适用的编译方法,10年后就显得过时了。由于缺乏兴趣,核心团队没有人对该库进行改进,而且Distutils对于编译Python和大多数项目来说已经足够了。需要高级工具链的人会使用其他工具,如SCons(http://scons.org/)。

改进工具链并非易事,因为存在基于Distutils的现有遗留系统。从头开始创建一个新的打包系统相当困难,因为Distutils是标准库的一部分,但引入向后兼容的更改也很难做好。改进是逐步进行的。像Setuptools和virtualenv这样的项目是在标准库之外创建的,Python本身也进行了一些直接更改。

截至目前,仍然能看到这些更改留下的痕迹,很难确切知道事情应该如何做。例如, pyvenv 命令在Python 3早期版本中被添加,然后在Python 3.6中被移除,但Python仍然自带虚拟环境模块,同时也有像virtualenv这样的工具来简化操作。

最好使用标准库之外开发和维护的工具,因为它们的发布周期比Python短。也就是说,标准库的更改需要几个月才能发布,而第三方项目的更改可以更快地提供。现在,所有被视为事实上的标准打包工具链的第三方项目都被归到了PyPA(https://www.pypa.io)伞形项目下。

除了开发工具,PyPA还通过为Python提出PEP并开发早期规范来改进打包标准,可参考https://www.pypa.io/en/latest/roadmap/。在打包和依赖管理方面经常会有新工具和实验,无论它们是否流行,都能让我们学到新东西。在本章中,我们将使用核心的、知名的工具。

下面是Python打包相关概念的总结表格:
| 概念 | 定义 |
| ---- | ---- |
| Python包 | 包含Python模块的目录树,可导入,是模块命名空间一部分 |
| Python项目 | 包含多个包、模块和其他资源,是要发布的内容 |
| Python应用程序 | 可通过用户界面直接使用的Python项目 |
| Python库 | 为其他Python项目提供功能,无直接最终用户界面 |

以下是获取Slack令牌的流程mermaid图:

graph LR
    A[用户点击登录链接] --> B[重定向到Slack]
    B --> C[用户授权]
    C --> D[重定向回应用程序回调端点]
    D --> E[获取临时代码]
    E --> F[请求转换为访问令牌]
    F --> G[存储令牌或发送到数据服务]

构建仪表板与Python项目打包运行

6. 微前端架构的优势与挑战

微前端架构具有显著的优势,但也面临一些挑战,下面对其进行详细分析:
| 方面 | 优势 | 挑战 |
| ---- | ---- | ---- |
| 开发效率 | 不同团队专注于不同组件,可独立发布新功能和修复漏洞,无需大规模跨团队协调 | 团队需确保UI集成方式一致,接受相同数据并返回所需大小的UI元素,增加了一定协调成本 |
| 代码管理 | 每个微前端组件可独立维护,更改局限于自身仓库和服务,便于管理 | 若组件过多,管理多个仓库和服务会增加复杂度 |
| 系统扩展性 | 可灵活添加或更换后端服务和前端框架,系统扩展性强 | 微前端架构较新,最佳实践和术语不稳定,学习和应用成本较高 |
| 安全性 | 可将敏感服务(如DataService)隐藏在仪表板后,提高安全性 | 若代理所有流量通过仪表板,可能导致单点故障,影响系统可用性 |

微前端架构的优势使其在大型项目和复杂系统中具有广泛的应用前景,但开发团队需要充分考虑其挑战,采取相应的措施来应对。

7. Python项目打包工具的选择

在Python项目打包中,选择合适的工具至关重要。由于标准库中的Distutils存在缺陷,我们推荐使用标准库之外由PyPA管理的工具,以下是一些常见工具的对比:
| 工具 | 特点 | 适用场景 |
| ---- | ---- | ---- |
| Setuptools | 增强了Distutils的功能,支持依赖管理和包分发 | 适用于大多数Python项目的打包和分发 |
| virtualenv | 用于创建独立的Python虚拟环境,隔离项目依赖 | 适合在开发和测试环境中使用,避免不同项目依赖冲突 |
| pip | 用于安装和管理Python包,是Python社区广泛使用的包管理工具 | 可与其他工具配合使用,方便安装项目所需的各种包 |

选择工具时,需要根据项目的具体需求和特点进行综合考虑。例如,对于小型项目,使用Setuptools和pip可能就足够了;而对于大型项目,可能还需要结合virtualenv来管理项目依赖。

8. 微前端架构与Python项目打包的结合应用

将微前端架构与Python项目打包结合起来,可以构建出高效、灵活且易于维护的系统。以下是结合应用的步骤和注意事项:
- 步骤
1. 使用微前端架构将前端拆分为多个独立的组件,每个组件由不同团队负责开发和维护。
2. 对每个微前端组件进行单独的Python项目打包,使用合适的工具(如Setuptools)将其封装为可分发的包。
3. 将打包好的微前端组件部署到相应的环境中,并使用nginx等负载均衡器进行路由配置。
4. 在Python后端项目中,使用pip安装所需的微前端组件包,并进行集成和测试。
- 注意事项
- 确保微前端组件与后端服务之间的数据交互格式一致,避免出现兼容性问题。
- 在部署过程中,要注意各个组件的依赖关系,确保所有依赖都能正确安装和配置。
- 建立有效的监控和日志系统,及时发现和解决系统运行过程中出现的问题。

以下是微前端架构与Python项目打包结合应用的mermaid流程图:

graph LR
    A[设计微前端架构] --> B[开发微前端组件]
    B --> C[Python项目打包]
    C --> D[部署组件]
    D --> E[配置负载均衡器]
    E --> F[后端项目集成]
    F --> G[测试与监控]
9. 总结

通过对微前端架构和Python项目打包的介绍,我们了解到微前端架构能够提高开发效率、增强系统的扩展性和可维护性,而Python项目打包工具的发展使得项目的发布和分发更加便捷。在实际应用中,我们可以将两者结合起来,构建出更加高效、灵活的系统。

在构建仪表板时,我们采用了微前端架构,将不同功能模块拆分为独立的组件,同时使用Slack的OAuth2 API进行用户身份验证,并通过生成JWT令牌来实现与其他微服务的安全通信。在Python项目打包方面,我们推荐使用由PyPA管理的工具,根据项目需求选择合适的工具进行打包和分发。

未来,随着技术的不断发展,微前端架构和Python项目打包工具将不断完善,为开发者提供更加优质的开发体验和更强大的功能支持。开发者应持续关注这些技术的发展动态,不断学习和实践,以适应不断变化的技术环境。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值