go

Go项目实战

Posted by Sutdown on March 1, 2025
  • qimi liwenzhou 博客
  • 有很多点还没搞清楚,包括业务语法,有待加强

简历

  • 关键在于登录注册投票帖子展示等功能的实现
  • 然后一些库函数,一些算法等
  • 再就是性能分析

库函数

viper

Viper是 Go 语言中一款功能强大的配置管理库,旨在简化应用程序的配置处理。它支持多种配置文件格式,包括 JSON、TOML、YAML、HCL、envfile 和 Java properties 等。此外,Viper 还提供了从环境变量、命令行标志、远程配置系统(如 etcd 或 Consul)以及直接在代码中设置配置值的功能。

sqlx

sqlx 是 Go 语言中的一个库,扩展了标准的 database/sql 库,简化了数据库操作,提供了更多的功能和便捷的方法,尤其是在处理结构体与数据库表之间的映射时。它的目标是提供比原生 database/sql 更简洁、更高效的数据库操作方式,同时仍保持与标准库的兼容性。

lumberjack

lumberjack 是 Go 语言中的一个库,主要用于 日志轮转(log rotation)和 日志文件管理。它提供了自动的日志文件切割功能,可以避免日志文件过大,从而有效管理日志的存储空间

zap
  • 能够将事件记录到文件中,而不是应用程序控制台。
  • 日志切割-能够根据文件大小、时间或间隔等来切割日志文件。
  • 支持不同的日志级别。例如INFO,DEBUG,ERROR等。
  • 能够打印基本信息,如调用文件/函数名和行号,日志时间等
validator

validator 是一个用于 Go 语言的强大且灵活的数据验证库,通常用于验证结构体中的字段是否符合某些规则。它通过标签(tags)来指定验证规则,支持各种常见的数据验证功能,例如字符串长度、邮箱格式、正则表达式匹配、数值范围等。

设计理念

基于雪花算法生成用户id

分布式ID生成器
  • 全局唯一性:不能出现有重复的ID标识,这是基本要求
  • 递增性:确保生成ID对于用户或业务是递增的
  • 高可用性:任何情况都能生成正确的ID
  • 高性能性,高并发环境下表现良好

雪花算法 - 维基百科,自由的百科全书

bwmarrn/snowflake
1bit Unused | 41bit 时间戳 | 10bit 机器ID | 12bit 序列号

snoy/snoyflake

1 + 39 +8(序列号) + 16(机器id)

用户认证

HTTP是一个无状态的协议,一次请求结束后,下次再发送服务器就不知道请求由谁发送了(一个IP不代表一个用户),在Web应用中,用户的认证和鉴权十分重要。

  • 客户端使用用户名,密码验证
  • 服务端验证用户名,密码正确后生成并存储Session,将SessionID通过Cookie返回客户端
  • 客户端访问需要认证的接口时在Cookie中携带SessionID
  • 服务端通过SessionID查找Session并进行鉴权,返回客户端需要的数据

但是,基于session方式存在多种问题:

  • 服务端需要存储session在内存中(需要快速查找),用户多时占用服务器资源较多。
  • 当需要扩展时,创建session的服务器可能不是验证session的服务器,还需要共享所有的session
  • 由于客户端使用cookie存储sessionID,跨域场景下需要进行兼容处理,同时这种方式以防范CSRF攻击
Token认证模式

基于Token的无状态会话管理,服务端不再存储信息,逻辑如下

  • 客户端使用用户名,密码认证
  • 服务端验证用户名密码是否正确,生成Token返回客户端
  • 客户端保存Token,访问需要认证的接口时在URL参数或者HTTP header种加入token
  • 服务端解码Token进行鉴权,返回客户端需要的数据

解决了Session会话管理带来的问题

  • 服务端不需要存储和用户鉴权有关的信息,鉴权信息会被加密到token种,服务端只读取token包含的鉴权信息即可
  • 避免了共享session导致的不易扩展
  • 不需要依赖cookie,避免了相关的CSRF攻击
  • 使用CORS可以快速解决跨域问题

JWT

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于安全地在各方之间传递信息。JWT 通常用于身份认证和授权场景,尤其是在 Web 应用和 API 中。它可以作为一种紧凑、URL 安全的方式来表示声明(claims),并且通常由三部分组成:头部、有效载荷和签名。

JWT 的组成

一个 JWT 通常由三部分组成

  1. Header通常包含算法和类型(JWT)(Base64 编码):eyJhbGciOiAiSFMyNTYiLCJ0eXAiOiAiSldUIn0
  2. Payload包含用户信息或声明(如用户 ID、角色等)(Base64 编码):eyJzdWIiOiAiMTIzNDU2Nzg5MCIsIm5hbWUiOiAiSm9obiBEb2UiLCJpYXQiOiAxNTE2MjM5MDIyfQ
  3. Signature使用密钥对前两部分进行加密,确保数据完整性f:使用密钥 "secret" 对前两部分进行加密。

分别用点(.)分隔,格式如下:

1
header.payload.signature
特点
  • 自包含(Self-contained):JWT 将所有必要的信息(如用户身份、权限等)存储在令牌中,因此服务器无需存储会话信息。它是自包含的。
  • 无状态(Stateless):JWT 不需要服务器保持会话状态。服务器只需要验证 JWT 的有效性,无需存储用户的任何会话数据。
  • 紧凑性(Compact):由于采用了 Base64 编码,JWT 非常小且适合在 URL、HTTP 头或 Cookie 中传输。
  • 可验证性(Verifiable):JWT 的签名部分确保了数据的完整性和真实性。通过公共密钥或共享密钥可以验证 JWT 是否被篡改。
  • 跨域支持:JWT 是通过 HTTP 头部传递的,可以轻松支持跨域请求,在 RESTful API 或微服务架构中非常常见。
缺点
  • 暴露信息:JWT 的有效载荷部分没有加密,任何人都可以解码 JWT 查看其中的信息。如果需要存储敏感信息,必须使用加密的 JWT(JWE)。
  • 不可撤销:一旦 JWT 被签发,直到它过期之前,服务器无法撤销它。因此,如果用户登出或权限改变,需要采用额外的机制来处理。
  • 过期问题:如果没有设置合理的过期时间,JWT 可能会在长时间内有效,这增加了安全风险。

后端需要对外提供一个刷新Token的接口;前端需要实现一个当access Token过期时,自动刷新Token接口获取新Assess Token的拦截器。

redis实现投票,什么时候用mysql,什么时候用redis