写点什么

「金三银四」这些面试题,看看你会答几道?

作者:王中阳Go
  • 2023-03-09
    北京
  • 本文字数:5841 字

    阅读完需:约 19 分钟

「金三银四」这些面试题,看看你会答几道?

前言


昨天群友问我能不能整理 Go 主流框架方面的面试题,安排!


这篇文章整理了 gRPC、GoFrame、GoZero、GoMicro、GORM、Gin 等主流框架的 30 道面试题。


需要大厂面经的朋友们也可以关注我的公众号:程序员升职加薪之旅

gRPC

1.gRPC 是什么,有哪些优点?

gRPC 是一种高性能、开源的远程过程调用(RPC)框架,它可以使不同平台和语言之间的服务相互通信。它的优点包括:高效性、跨平台、异步流处理、支持多种语言、安全、易于使用和开源。

2.gRPC 和 REST 的区别是什么?

REST 是基于 HTTP 协议的一种风格,而 gRPC 是一个独立于协议的 RPC 框架。 REST 基于资源的状态转移,使用标准的 HTTP 方法,而 gRPC 使用协议缓冲区(Protocol Buffers)进行序列化和反序列化。 gRPC 支持异步流处理和双向流,而 REST 通常只支持请求/响应模式。

3.Protocol Buffers 是什么,为什么它被用于 gRPC 中?

Protocol Buffers 是一种语言中立、平台中立、可扩展的序列化格式,它可以用于数据交换和持久化。它被用于 gRPC 中,因为它可以实现高效的序列化和反序列化,从而提高了 gRPC 的性能和效率。

4.gRPC 的流程是什么?

gRPC 流程分为四个步骤:定义服务、生成源代码、实现服务、启动服务。首先,需要定义要实现的服务及其接口,使用 Protocol Buffers 编写接口定义文件。其次,使用编译器生成客户端和服务器端的源代码。然后,实现生成的接口。最后,启动服务器并将其部署在适当的位置。

5.gRPC 支持哪些类型的序列化?

gRPC 支持两种类型的序列化:二进制(使用 Protocol Buffers)和 JSON。其中,二进制序列化在效率和性能方面比 JSON 序列化更优秀。但是,JSON 序列化在可读性方面更好,可以方便地进行调试和测试。

GoFrame

1.什么是 GoFrame?与 Go 标准库有什么区别?

GoFrame 是一个强大的 Go Web 应用开发框架,它提供了一系列优秀的功能模块和常用工具,方便开发者快速构建高性能、高可用的 Web 应用程序。


相较于 Go 标准库,GoFrame 提供了更多的功能模块,例如:ORM、Cache、Session、WebSocket、邮件发送等等。此外,GoFrame 也提供了更友好的 API 和更好的性能。

2.goframe 框架中,如何使用中间件?

在 goframe 框架中使用中间件很简单。只需要在路由定义时使用中间件函数,例如:


s := g.Server()s.Group("/", func(group *ghttp.RouterGroup) {    group.Middleware(MiddlewareFunc)    group.ALL("/user", UserHandler)})
复制代码

3.goframe 框架中,如何实现定时任务?

在 goframe 框架中实现定时任务很容易。可以使用 gcron 插件。该插件提供了简单的 API 用于创建和管理定时任务,例如:


// 创建定时任务s := gcron.NewScheduler()s.Every(1).Hour().Do(TaskFunc)
// 开始定时任务s.Start()
复制代码

4.goframe 框架中,如何实现文件上传和下载?

在 goframe 框架中实现文件上传和下载很容易。可以使用 ghttp 的相关方法进行操作,例如:


// 文件上传uploadFile, err := r.UploadFile("file")if err != nil {    return err}uploadFile.Save("/path/to/save")
// 文件下载r.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))r.Response().ServeFile(filepath)
复制代码

5.GoFrame 中的 gvalid 组件是什么?如何使用?

goframe 框架提供了功能强大、使用便捷、灵活易扩展的数据/表单校验组件,由 gvalid 组件实现。


gvalid 组件实现了非常强大的数据校验功能,内置了数十种常用的校验规则,支持单数据多规则校验、多数据多规则批量校验、自定义错误信息、自定义正则校验、自定义校验规则注册、支持 i18n 国际化处理、支持 struct tag 规则及提示信息绑定等等特性,是目前功能最强大的 Go 数据校验模块。

Go-Zero

1.Go-Zero 是什么?它的主要功能是什么?它与其他 Go 框架有什么不同?

Go-Zero 是一个基于 Go 语言的微服务开发框架。它旨在提供简单、高效和可靠的微服务开发解决方案。Go-Zero 主要功能包括 RPC、缓存、限流、熔断、监控等。相较于其他 Go 框架,如 Gin 或 Beego,Go-Zero 更加专注于微服务开发,并提供了更多的开箱即用的功能。

2.go-zero 中如何实现 JWT 认证授权?

go-zero 中提供了 go-jwt 包来实现 JWT 认证授权。具体步骤如下:


1)定义一个 Claims 结构体,包含需要存储到 JWT token 中的信息。


2)通过 jwt.NewHS256([]byte("your-secret"))创建一个 JWT 签名实例,将 Claims 结构体转换成 token 字符串。


3)通过 jwt.ParseHS256(token, []byte("your-secret"))验证 token,并返回解析后的 Claims 结构体。

3.如何使用 go-zero 实现异步任务?

go-zero 中提供了 go-queue 包来实现异步任务。具体步骤如下:


1)创建一个 Redis 连接池。


2)通过 queue.New(queueConfig, redisConfig)创建一个队列实例。


3)通过 producer := queue.NewProducer()创建一个生产者实例。


4)通过 consumer := queue.NewConsumer(queueConfig, redisConfig)创建一个消费者实例。


5)通过 producer.Enqueue(job)将任务放入队列。


6)通过 consumer.Consume(processor)处理队列中的任务。

4. 如何使用 go-zero 实现分布式缓存?

go-zero 中提供了 go-cache 包来实现分布式缓存。具体步骤如下:


1)创建一个 Redis 连接池。


2)通过 cache.New(cacheConfig, redisConfig)创建一个缓存实例。


3)通过 cache.Set(key, value, expireTime)将数据存入缓存中。


4)通过 cache.Get(key)从缓存中获取数据。

5.如何使用 go-zero 实现限流?

go-zero 中提供了 go-ratelimit 包来实现限流。具体步骤如下:


1)通过 rate.NewLimiter(rate.Every(time.Second), 100)创建一个限流器实例,限制每秒处理 100 个请求。


2)通过 limiter.Allow()方法判断当前请求是否被允许,若被允许则处理请求,否则返回错误提示。

GIN

1.Gin 框架有什么特点?

Gin 是一个基于 Go 语言的 Web 框架,它提供了一些轻量级的工具,使得编写高性能的 Web 应用程序变得非常容易。Gin 具有快速的路由器,中间件支持和错误管理功能,同时还提供了自动化的 API 文档生成和参数绑定等功能。

2.Gin 框架中的中间件是什么?

中间件是 Gin 框架的一个重要概念,它是一种在处理请求之前或之后执行的函数。中间件通常用于处理请求,如身份验证,日志记录和性能监测等。在 Gin 框架中,中间件可以按照需要在路由器级别或全局级别进行注册和使用。

3.如何在 Gin 框架中处理跨域请求?并给出代码

Gin 框架提供了一个 cors 中间件,可以用来处理跨域请求。在使用 cors 中间件时,可以指定允许跨域请求的源地址,允许的请求方法,允许的头信息等。例如:


r := gin.Default()r.Use(cors.New(cors.Config{  AllowOrigins: []string{"http://localhost:8080"},  AllowMethods: []string{"PUT", "PATCH", "GET", "POST", "DELETE"},  AllowHeaders: []string{"Origin"},}))
复制代码

4.如何在 Gin 框架中实现文件上传?

在 Gin 框架中,可以使用 MultipartForm 函数来处理文件上传。MultipartForm 函数会自动解析 multipart/form-data 格式的表单数据,并将文件保存在指定的目录中。例如:


func UploadFile(c *gin.Context) {    file, err := c.FormFile("file")    if err != nil {        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})        return    }    filename := filepath.Base(file.Filename)    if err := c.SaveUploadedFile(file, filename); err != nil {        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})        return    }    c.JSON(http.StatusOK, gin.H{"filename": filename})}
复制代码

5.GoFrame 中的 gvalid 模块是什么?如何使用?

goframe 框架提供了功能强大、使用便捷、灵活易扩展的数据/表单校验组件,由 gvalid 组件实现。


gvalid 组件实现了非常强大的数据校验功能,内置了数十种常用的校验规则,支持单数据多规则校验、多数据多规则批量校验、自定义错误信息、自定义正则校验、自定义校验规则注册、支持 i18n 国际化处理、支持 struct tag 规则及提示信息绑定等等特性,是目前功能最强大的 Go 数据校验模块。

5.如何在 Gin 框架中实现 JWT 认证?

在 Gin 框架中,可以使用 jwt-go 库来实现 JWT 认证。JWT 认证流程通常包括登录,生成 token,验证 token 等步骤。在 Gin 框架中,可以使用中间件来实现 JWT 认证,例如:


func AuthMiddleware() gin.HandlerFunc {    return func(c *gin.Context) {        tokenString := c.GetHeader("Authorization")        if tokenString == "" {            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "Authorization header required"})            return        }
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) }
复制代码

GORM

1.GORM 如何实现一对多和多对多关系的映射?

对于一对多关系,可以使用 GORM 的 BelongsTo 和 HasMany 方法实现映射。比如:


type User struct {    ID        uint    Name      string    Addresses []Address}
type Address struct { ID uint UserID uint Address string}
// User 模型对应的表应该包含一个外键,指向 Address 表中的 UserID 字段// 使用 BelongsTo 和 HasMany 方法进行关联func (u *User) Addresses() []Address { var addresses []Address DB.Model(&u).Association("Addresses").Find(&addresses) return addresses}
func (a *Address) User() User { var user User DB.Model(&a).Association("User").Find(&user) return user}
复制代码


对于多对多关系,可以使用 GORM 的 ManyToMany 方法实现映射。比如:


type User struct {    ID       uint    Name     string    Articles []Article `gorm:"many2many:user_articles"`}
type Article struct { ID uint Title string Content string Users []User `gorm:"many2many:user_articles"`}
// User 和 Article 之间的关系通过 user_articles 表进行映射
复制代码

2.在使用 GORM 进行数据库查询时,如何避免 N+1 查询的问题?

N+1 查询问题指的是在查询关联表时,如果使用了嵌套循环进行查询,就会产生大量的 SQL 查询。为了避免这个问题,可以使用 GORM 的 Preload 方法预先加载关联数据。比如:


// 查询 Users 以及它们的 Addressesvar users []UserDB.Preload("Addresses").Find(&users)
复制代码


这个查询会一次性加载所有 User 和 Address 数据,避免了 N+1 查询问题。

3. 如何使用 GORM 进行事务管理?

GORM 的事务管理使用 Begin、Commit 和 Rollback 方法实现。比如:


tx := DB.Begin()defer func() {    if r := recover(); r != nil {        tx.Rollback()    }}()
// 在事务中执行一系列操作if err := tx.Create(&user).Error; err != nil { tx.Rollback() return err}
if err := tx.Create(&address).Error; err != nil { tx.Rollback() return err}
// 提交事务tx.Commit()
复制代码

4.GORM 的 Preload 方法和 Joins 方法有什么区别?在什么情况下使用哪种方法更好?

Preload 方法是在查询时预加载关联数据,而 Joins 方法是通过 SQL JOIN 语句连接多个表查询数据。Preload 方法适用于关联表较少、数据量不大的情况;而 Joins 方法适用于关联表较多、数据量较大的情况。

5.如何在 GORM 中使用原生 SQL 查询?

在 GORM 中,可以使用 Raw 方法来执行原生 SQL 查询。Raw 方法接受一个 SQL 查询字符串和可选的参数列表,并返回一个 *gorm.DB 对象,可以使用该对象进行进一步的查询操作。


下面是一个使用 Raw 方法执行原生 SQL 查询的示例:


import "gorm.io/gorm"
// ...
var users []Userresult := db.Raw("SELECT * FROM users WHERE age > ?", 18).Scan(&users)if result.Error != nil { // 处理错误}
复制代码


在上面的示例中,我们使用 Raw 方法执行了一个简单的 SQL 查询,它将返回所有年龄大于 18 岁的用户。Scan 方法用于将查询结果映射到一个 []User 对象中。


还可以使用 Exec 方法来执行不需要返回值的 SQL 查询,如插入、更新或删除数据:


result := db.Exec("DELETE FROM users WHERE age < ?", 18)if result.Error != nil {    // 处理错误}
复制代码


在上面的示例中,我们使用 Exec 方法执行一个删除语句,它将删除所有年龄小于 18 岁的用户。由于这个 SQL 不需要返回值,我们只需检查 result.Error 是否为 nil 来判断查询是否成功。


请注意,使用原生 SQL 查询可能会使代码更难以维护和调试,因为它们不受 GORM 的自动迁移和其他便利功能的支持。因此,应该尽可能地使用 GORM 提供的高级查询功能。

Go-Micro

1.什么是 go-micro?

go-micro 是一个微服务框架,它可以用于构建可伸缩和可维护的微服务应用程序。它支持多种语言和传输协议,并提供了一系列服务发现、负载均衡、消息传递和远程过程调用(RPC)等基础设施功能。

2.go-micro 支持哪些传输协议?

go-micro 支持多种传输协议,包括 HTTP、TCP 和 NATS。其中,HTTP 和 TCP 协议适用于内部服务之间的通信,而 NATS 协议则适用于跨网络边界的通信。

3.如何使用 go-micro 进行服务发现和负载均衡?

go-micro 内置了服务发现和负载均衡功能,可以通过调用相关 API 实现。例如,可以使用 go-micro 的服务发现 API 来查找已注册的服务,并使用负载均衡 API 来将请求分配到多个实例之间。

4.go-micro 支持哪些消息传递方式?

go-micro 支持多种消息传递方式,包括同步和异步消息传递。同步消息传递使用 RPC 机制,而异步消息传递则使用消息队列和事件驱动模式。

5.如何使用 go-micro 进行测试?

go-micro 提供了一系列测试工具和测试框架,可以用于测试微服务应用程序的各个组件。其中,mock 测试工具可以用于模拟服务接口和行为,以及对服务进行单元测试。另外,go-micro 还提供了一些集成测试工具,例如 Docker 和 Kubernetes,可以用于测试多个服务之间的交互。

总结

有志者,事竟成,破釜沉舟,百二秦关终属楚。


苦心人,天不负,卧薪尝胆,三千越甲可吞吴。


就算就业环境再好,也有人找不到工作;即使就业环境不好,也肯定有人能找到工作。


停止抱怨和焦虑,要想找到好工作:项目+算法+八股,都要硬,学起来吧!兄弟们加油。

成功上岸

如果你不知道如何写好简历,不知道如何在面试中做好自我介绍和项目介绍:可以关注我的公众号:程序员升职加薪之旅


也欢迎大家关注我的 InfoQ 账号,点赞、留言、转发。


你的支持,是我更文的最大动力!

发布于: 2023-03-09阅读数: 37
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

【微信】wangzhongyang1993【公众号】程序员升职加薪之旅【成就】InfoQ专家博主👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论 (1 条评论)

发布
用户头像
这篇文章整理了gRPC、GoFrame、GoZero、GoMicro、GORM、Gin等主流框架的30道面试题。
就算就业环境再好,也有人找不到工作;即使就业环境不好,也肯定有人能找到工作。
停止抱怨和焦虑,要想找到好工作:项目+算法+八股,都要硬,学起来吧!兄弟们加油。
2023-03-09 11:05 · 北京
回复
没有更多了
「金三银四」这些面试题,看看你会答几道?_Go_王中阳Go_InfoQ写作社区