无题
Gohub开发
title: Gohub开发
categories: Go语言
tags: 项目开发
abbrlink: 25069
date: 2024-04-15 15:41:08
本项目为从零构建一个高性能、功能齐全的 API 程序框架,主体内容和第一个项目相似。但是并没有做前端的内容,只针对相应功能做了 API 开发。
本项目主要设计一下三部分的知识点:
- API 开发
- 命令行开发
- 构建高效率的程序结构
主要功能为:
- 用户的注册和登录
- 安全验证码和图片验证码
- JWT 授权
- 用户修改个人信息
项目统计
实现路由
| 请求方法 | API 地址 | 说明 |
|---|---|---|
| POST | /api/v1/auth/login/using-phone | 短信 + 手机号登录 |
| POST | /api/v1/auth/login/using-password | 手机号、用户名、邮箱 + 密码 |
| POST | /api/v1/auth/login/refresh-token | 刷下 Token |
| POST | /api/v1/auth/password-reset/using-email | 邮件密码重置 |
| POST | /api/v1/auth/password-reset/using-phone | 短信验证码密码重置 |
| POST | /api/v1/auth/signup/using-phone | 使用手机号注册 |
| POST | /api/v1/auth/signup/using-email | 使用邮箱注册 |
| POST | /api/v1/auth/signup/phone/exist | 手机号是否已注册 |
| POST | /api/v1/auth/signup/email/exist | email 是否已支持 |
| POST | /api/v1/auth/verify-codes/phone | 发送短信验证码 |
| POST | /api/v1/auth/verify-codes/email | 发送邮件验证码 |
| POST | /api/v1/auth/verify-codes/captcha | 获取图片验证码 |
| GET | /api/v1/user | 获取当前用户 |
| GET | /api/v1/users | 用户列表 |
| PUT | /api/v1/users | 修改个人资料 |
| PUT | /api/v1/users/email | 修改邮箱 |
| PUT | /api/v1/users/phone | 修改手机号 |
| PUT | /api/v1/users/password | 修改密码 |
| PUT | /api/v1/users/avatar | 上传头像 |
| GET | /api/v1/categories | 分类列表 |
| POST | /api/v1/categories | 创建分类 |
| PUT | /api/v1/categories/:id | 更新分类 |
| DELETE | /api/v1/categories/:id | 删除分类 |
| GET | /api/v1/topics | 话题列表 |
| POST | /api/v1/topics | 创建话题 |
| PUT | /api/v1/topics/:id | 更新话题 |
| DELETE | /api/v1/topics/:id | 删除话题 |
| GET | /api/v1/topics/:id | 获取话题 |
| GET | /api/v1/links | 友情链接列表 |
第三方依赖
使用到的开源库:
- gin —— 路由、路由组、中间件
- zap —— 高性能日志方案
- gorm —— ORM 数据操作
- cobra —— 命令行结构
- viper —— 配置信息
- cast —— 类型转换
- redis —— Redis 操作
- jwt —— JWT 操作
- base64Captcha —— 图片验证码
- govalidator —— 请求验证器
- limiter —— 限流器
- email —— SMTP 邮件发送
- aliyun-communicate —— 发送阿里云短信
- ansi —— 终端高亮输出
- strcase —— 字符串大小写操作
- pluralize —— 英文字符单数复数处理
- faker —— 假数据填充
- imaging —— 图片裁切
自定义的包
现在来看下我们自建的库:
- app —— 应用对象
- auth —— 用户授权
- cache —— 缓存
- captcha —— 图片验证码
- config —— 配置信息
- console —— 终端
- database —— 数据库操作
- file —— 文件处理
- hash —— 哈希
- helpers —— 辅助方法
- jwt —— JWT 认证
- limiter —— API 限流
- logger —— 日志记录
- mail —— 邮件发送
- migrate —— 数据库迁移
- paginator —— 分页器
- redis —— Redis 数据库操作
- response —— 响应处理
- seed —— 数据填充
- sms —— 发送短信
- str —— 字符串处理
- verifycode —— 数字验证码
知识点
- 配置信息(使用 Viper,支持 .env 和 config 目录 )
- API 版本
- API 错误码
- API 限流
- 支持秒、分钟、小时、天级的请求限制
- 支持返回 API 请求量标头(限制数,剩余量、重置时间)
- 注册登录
- 注册
- 判断手机是否注册
- 判断 Email 是否注册
- 支持手机 + 短信验证码进行注册
- 支持使用邮箱注册账号
- 登录
- 支持手机 + 短信进行登录
- 支持密码登录(手机号、Email、用户名任选)
- 支持更加安全的 Token Refresh 机制
- 找回密码
- 支持使用手机 + 短信验证码找回
- 支持使用邮箱 + 邮箱验证码找回
- 注册
- JWT 授权
- 整个应用使用命令行模式(默认运行 web 服务)
- 内置命令行( cobra,对比 cli 和 cobra)
- key 命令生成 app key
- make 命令
- make seeder —— 生成数据填充
- make policy —— 生成授权文件
- make apicontroller —— 生成 Restful API 控制器
- make model —— 生成模型文件
- make request —— 生成请求验证文件
- make factory —— 生成模型工厂文件
- make cmd —— 生成自定义命令文件
- make migration —— 生成数据库迁移文件
- seed 数据填充
- seed 所有数据
- seed 单条数据
- 支持使用 faker 填充假数据
- 支持模型工厂( factory )
- migrate 数据库迁移
- up —— 执行迁移
- rollback (down) —— 回滚上一步执行的迁移
- fresh —— 删除所有表,然后执行所有迁移
- reset —— 回滚所有迁移
- refresh —— 回滚所有迁移,然后再执行所有迁移
- cache 缓存处理
- cache clear —— 清除缓存
- cache forget —— 忘记某个 KEY 对应的缓存
- 分页
- 支持返回上下页链接,方便客户端调用
- Cache 缓存包
- 支持 redis 缓存
- 使用 interface ,支持使用多驱动
- Redis 操作
- 安全验证码
- Email (发送邮箱,使用 Mailhog 进行测试)
- 手机验证码(发送手机短信)
- 内置 Redis 驱动,以接口方式编写,支持多驱动
- 图片验证码,防机器人滥用
- 支持通过配置信息自定义复杂度
- 内置 Redis 驱动,以接口方式编写,支持多驱动
- 日志记录
- 集成 zap 高性能日志库
- 支持命令行记录(方便开发时快速定位问题)
- 命令行日志高亮
- 支持文件记录(多文件和按日期分隔)
- 记录 gorm 的 query log
- 记录 HTTP 请求 log
- Panic Recovery 中间件
- 合理的日志等级(debug, info, error, panic, fatal)
- Policy 授权策略结构
- Request 请求验证方案
- 支持 JSON 请求、表单请求、URL Query
- API 图片上传
- 图片裁切
- 数据库支持 mysql 和 sqlite
总结
由于本项目是一个完全只涉及到 API 设计的内容,所以测试功能是否符合预期则是采用了 Postman 这款测试软件,有关 Redis 的可视化则是采用了 Another Redis Desktop Manager。
考虑到篇幅的问题,项目的知识点总结会分开来写。所以这篇文章是用来提醒我去学习的。
Gohub——日志
title: Gohub——日志
abbrlink: 24717
date: 2024-04-18 22:50:36
categories: Go语言
tags: 项目开发
正经人谁写日记啊?
欸欸欸,不好意思,来错片场了(手动狗头)。今天介绍的是项目中必不可少的一部分——日志。
日志系统
虽然正经人不写日记,但是正经项目一定要记录日志。总所周知啊,Gohub 就是一个非常正经的项目,虽然还没有到企业级这么高的层次,但是也差不多了。
在 Gohub 中,我们使用日志来记录整个系统的运行情况,可能但不限于:
- HTTP 请求数据
- 数据库 SQL 请求日志
- Panic/Error 错误日志
- 请求第三方接口日志(发送短信、发送邮件等)
- ……
好了,是时候掏出祖传的几个问题了,什么是日志?该怎么设置日志?下面将会一一解答。
什么是日志
日志系统是一种记录系统活动、事件或消息的工具或机制。在计算机领域,日志系统通常用于记录应用程序、操作系统或者其他软件系统的运行时信息。这些信息可以包括错误、警告、调试信息、用户操作记录等等。
日志系统的主要目的是帮助开发人员或管理员了解系统的状态和运行情况,以便进行故障排除、性能优化、安全审计等工作。通过分析日志,可以追踪问题的根源,监视系统的健康状况,并且可以在系统发生故障或异常时进行及时的响应和处理。
日志系统通常具有以下特点:
- 可配置性: 可以根据需求配置日志记录的级别、格式、存储位置等参数。
- 实时性: 能够实时记录系统的运行状态,以便及时发现问题。
- 可扩展性: 能够处理大量的日志数据,并支持水平扩展以应对不断增长的系统负载。
- 安全性: 对日志数据进行安全存储和访问控制,以防止未经授权的访问或篡改。
- 分析性: 提供日志分析工具或接口,帮助用户对日志数据进行搜索、过滤、统计、可视化等操作。
常见的日志系统包括开源项目如ELK Stack(Elasticsearch、Logstash、Kibana)、Splunk、Fluentd等,以及云服务提供商提供的日志管理服务。
使用场景
本地开发
本地开发时,虽然我们可以很方便地使用 Debuger 来调试程序,但是日志将会是我们最廉价】最便捷地作物定位工具。
线上环境
日志是程序在生产环境下的健康监控。当程序出错时,或者某块业务逻辑出现问题,我们将依赖日志来知道具体哪一行代码出了问题。
如何记录?
| 使用环境 | 记录的载体 | 说明 |
|---|---|---|
| 开发环境(local) | 命令行终端 | 高亮、打印调用堆栈 |
| 线上环境(production) | 记录到日志文件 | JSON 格式,方便导入专业的日志工具 |
日志系统在计算机领域有广泛的使用场景,以下是一些常见的应用场景:
故障排查与调试: 当系统出现错误或异常时,日志可以记录错误信息、异常堆栈跟踪等,帮助开发人员快速定位并修复问题。
性能优化: 通过分析系统的性能日志,可以了解系统各个组件的性能瓶颈,从而进行优化,提升系统整体性能。
安全审计与监控: 日志记录系统的操作、访问权限、安全事件等信息,有助于进行安全审计和监控,及时发现潜在的安全威胁。
用户行为分析: 在网络应用或移动应用中,记录用户的操作行为可以帮助分析用户偏好、行为趋势,从而进行个性化推荐、用户体验优化等工作。
合规性需求: 许多行业或政府监管机构要求企业记录和保留特定类型的数据,日志系统可以满足这些合规性需求,并提供必要的审计跟踪。
容灾备份与恢复: 日志记录系统的备份和恢复功能可以帮助恢复因硬件故障、自然灾害或人为错误导致的数据丢失或损坏。
业务分析与决策支持: 通过分析系统产生的日志数据,可以了解业务运营情况、用户行为趋势等,为业务决策提供数据支持。
监控与警报: 基于日志数据设定监控规则,当系统出现异常或达到预定的阈值时,触发警报并通知相关人员进行处理。
这些场景只是日志系统的一部分应用,实际上日志系统在各个领域都有着重要的作用,帮助保障系统的稳定性、安全性和可靠性。
日志的等级
日志系统通常定义了不同的日志等级,用于标识和区分不同类型的日志信息,常见的日志等级包括:
| 日志等级 | 说明 |
|---|---|
| debug | 信息量大,一般调试时打开。系统模块详细运行的日志,例如 HTTP 请求、数据库请求、发送邮件、发送短信 |
| info | 业务级别的运行日志,如用户登录、用户退出、订单撤销。 |
| warn | 感兴趣、需要引起关注的信息。 例如,调试时候打印调试信息(命令行输出会有高亮)。 |
| error | 记录错误信息,用于记录程序发生的错误,这些错误可能导致程序无法正常工作,但不会使程序完全崩溃。Panic 或者 Error。如数据库连接错误、HTTP 端口被占用等。一般生产环境使用的等级。 |
日志等级规则:
- 日志等级在两个地方使用;
- 配置信息(config)中可以配置日志等级;
- 代码中调用不同的方法(
Debug()、Info()…)记录不同等级的日志。
- 日志等级具备过滤信息的属性;
- 配置信息里设置为高等级时,低于这个等级的信息将忽略。如日志等级设为 warn ,只有
Warn()和Error()方法记录的日志会有效,Debug()和Info()方法记录的日志会被忽略;
日志过载
日志过载是指日志系统产生的日志数量超出了处理能力或存储容量,导致系统无法有效地处理和存储所有的日志信息。这种情况可能会对系统的性能、稳定性和安全性造成负面影响。
日志过载可能出现在以下几种情况下:
异常情况爆发: 当系统遭遇大规模的异常或错误时,日志系统可能会产生大量的错误日志,导致日志系统过载。
频繁的警告信息: 如果系统产生大量的警告信息,而这些警告信息又被记录在日志中,就会增加日志系统的负担。
日志频率过高: 如果系统的日志频率过高,比如记录了过多的调试信息或者每个请求都生成了大量的日志记录,就会导致日志系统过载。
存储容量不足: 如果日志系统的存储容量不足以存储所有的日志数据,就会导致部分日志被丢弃或被覆盖,从而丧失了一部分重要的信息。
日志记录不当: 如果日志记录的内容过于冗长或者包含了大量的无关信息,会增加日志系统的负担,导致日志过载。
日志过载可能会导致以下问题:
- 性能下降: 过多的日志记录会占用系统资源,降低系统的性能和响应速度。
- 数据丢失: 如果日志系统无法处理所有的日志数据,部分重要的日志信息可能会被丢弃,导致问题的排查和分析变得困难。
- 安全风险: 日志过载可能会导致系统无法及时记录和响应安全事件,增加系统遭受攻击的风险。
为了避免日志过载,需要合理配置日志系统的参数,包括日志等级、存储策略、日志格式等,并定期清理和归档历史日志数据,确保日志系统能够有效地处理和存储日志信息。
记录日志的行为完全掌控在开发者手上。日志等级的错误使用,会导致日志信息过载,有违『快速定位问题』的设计初衷。
所以记录日志时,参与项目的开发者之间需要做好约定,或者说规范。
- 功能模块的详细运行情况,使用
Debug()方法,如 HTTP 请求日志、数据库 SQL 日志; - 业务级别的运行日志,使用
Info(),如果信息量太大,例如说一个请求会记录十几条Info()日志,要改用Debug(); - 控制好记录日志的量,切勿滥用,滥用会导致日志信息过载;
- 开发调试时,使用
Warn(),调试完成后记得删除调试信息; - 保持 warn 及以上日志级别的干净;
- 线上环境开启 error 等级,接到错误反馈时,再开启 debug 进行调试,调试完成后重新设置为 error 等级,保持线上日志的干净;
- 系统运行出错,才能使用
Error()记录,如数据库连接出错,或出现 500 错误。
杂项
.gitignore 文件
在开发 Go 项目时,我们的项目目录下经常会出现一些文件,例如编译文件、log 文件、编辑器配置文件、系统生成的一些文件,这些文件我们不希望提交到代码仓库中。
在任何当前工作的 Git 仓库中,每个文件都是这样的:
- 追踪的(tracked)- 这些是 Git 所知道的所有文件或目录。这些是新添加(用
git add添加)和提交(用git commit提交)到主仓库的文件和目录。 - 未被追踪的(untracked) - 这些是在工作目录中创建的,但还没有被暂存(或用
git add命令添加)的任何新文件或目录。 - 被忽略的(ignored) - 这些是 Git 知道的要全部排除、忽略或在 Git 仓库中不需要注意的所有文件或目录。本质上,这是一种告诉 Git 哪些未被追踪的文件应该保持不被追踪并且永远不会被提交的方法。
所有被忽略的文件都会被保存在一个 .gitignore 文件中。
.gitignore 文件是一个纯文本文件,包含了项目中所有指定的文件和文件夹的列表,这些文件和文件夹是 Git 应该忽略和不追踪的。
在 .gitignore 中,可以通过提及特定文件或文件夹的名称或模式来告诉 Git 只忽略一个文件或一个文件夹。也可以用同样的方法告诉 Git 忽略多个文件或文件夹。
配置信息的设置
在项目中,配置信息通常指的是一些参数、选项或设置,这些信息用于指导项目的行为、功能或外部依赖的配置。
Gohub 中的配置信息,将分为两个层级:
- env
- config
.env
一般来讲,项目会运行在多个环境下,例如:
- local —— 本地开发环境(我的机器上、其他开发同事的机器上)
- testing —— 自动化测试环境
- stage —— 接近线上环境的测试环境,方便其他成员访问和测试(编辑人员、产品经理、项目经理)
- production —— 线上生产环境
不同的环境下,我们将使用不同的配置。例如 local 环境里,发送短信使用的是测试账号,production 环境下,我们将使用验证了公司信息的发信账号。
.env 文件通常用于存储环境变量和敏感配置信息,它的作用包括:
- 配置管理:
.env文件可以用来集中管理项目的配置信息,如数据库连接信息、API 密钥、密码、密钥等。将这些配置信息存储在.env文件中有助于统一管理,减少硬编码,提高项目的灵活性和可维护性。 - 环境分离: 使用
.env文件可以将不同环境(如开发环境、测试环境和生产环境)的配置信息分离开来,避免在代码中硬编码不同环境下的配置,提高代码的可移植性和可重用性。 - 安全性:
.env文件通常位于项目根目录之外,并且可以通过.gitignore文件排除在版本控制系统中,从而保护敏感信息不被泄露到公共代码仓库中,提高项目的安全性。 - 便捷性: 通过
.env文件,可以方便地修改和管理项目的配置信息,无需修改源代码,减少了部署和维护的复杂性。 - 跨平台兼容性:
.env文件的格式通常是简单的键值对格式,易于解析和处理,可以跨多种编程语言和操作系统使用。
单独的 .env 的设计,是满足一台机器一套环境变量的需求。多个 .env 文件是满足一台机器上运行多套环境变量的需求。
开发时,除了 local 环境变量,很多时候还需要 testing 测试相关的环境变量,testing 的配置有别于 local 。例如测试时,一般需要使用不同的数据库,这样才能不污染我们的开发数据库。
我们可以利用程序参数,在命令行运行主程序时,传参 --env=testing 的参数,程序接收到这个参数后会读取 .env.testing 文件,而不是 .env 文件。
--env 的参数不需要限制值,取到以后直接读取对应的文件即可。以下是几个例子:
--env=testing读取 .env.testing 文件,用以在测试环境使用不同的数据库--env=production读取 .env.production 文件,用以在本地环境中调试线上的第三方服务配置信息(短信、邮件)
config
config 是将配置信息存放于 config 目录下,按照单独的逻辑区分单独的配置文件,例如数据库连接信息存放于 config/database.go 文件下。
config 里加载 .env 里的配置项,且可设置缺省值。
既然有 .env 文件,为何还要 config 呢?
config 可以提高配置方案灵活度。在 config 里,我们可以为每个配置项设置默认值。也可以做一些简单的数学运算,或者调用 Go 函数进行默认值的处理。我们甚至可以为配置项设置一个回调函数。
config 文件是要加入代码版本控制器中的,这些代码是固定的。如果要修改一个 config 配置项,就修改其对应的 .env 文件中的配置项即可。
总结
本文较短,主要记录了在 Gohub 开发设计日志时学到的相关的知识。其实在这个项目中用户使用的功能并没有什么太大的变化,即使增加了一些功能也都只是一种变式,核心并没有发生太大的变化,因此也就没有像之前一样逐个功能地去记录。那为什么还要去做新的项目呢,主要是因为舍友吧两个教程都买了,白嫖完了第一个肯定要继续白嫖第二个了。
做完第二个项目发现虽然一个叫 Gohub,一个叫 Goblog,两个看起来好像一样,但是实际开发地体验简直就是天上地下。Goblog 入门项目开发,学习怎么搭建 Web 应用;Gohub 才是真正的后端开发,更加专业,也让我学到了更多的东西。后悔啊,为什么上学期开始学 Go 的时候不好好写项目呢,要不然面试的时候也不会被拷打的那么惨了。不过这两个月确实还是学到了不少东西,比前两年半(没有玩梗,非常认真)加一起的都多了。
参考文献
传统艺能了,每篇文章都像一个模子里刻出来的,不过本文并没有参考什么文章,只参考了教程和 ChatGPT的回答。
