悠悠楠杉
责任链模式在Golang中的请求分发实践
首先定义一个处理器接口:
go
type Handler interface {
SetNext(handler Handler) Handler
Handle(request *ContentRequest) error
}
其中 ContentRequest 表示待处理的内容请求:
go
type ContentRequest struct {
Title string
Keywords []string
Description string
Body string
}
每一个具体的处理器都应实现该接口。例如,标题检查器负责验证标题长度和非法字符:
go
type TitleValidator struct {
next Handler
}
func (t *TitleValidator) SetNext(handler Handler) Handler {
t.next = handler
return handler
}
func (t *TitleValidator) Handle(request *ContentRequest) error {
if len(request.Title) == 0 {
return fmt.Errorf("标题不能为空")
}
if len(request.Title) > 100 {
return fmt.Errorf("标题长度不得超过100字符")
}
// 模拟敏感词检测
if strings.Contains(request.Title, "违法") {
return fmt.Errorf("标题包含敏感词汇")
}
if t.next != nil {
return t.next.Handle(request)
}
return nil
}
接下来是关键词过滤器,用于筛查黑名单关键词:
go
type KeywordFilter struct {
bannedWords map[string]bool
next Handler
}
func NewKeywordFilter() *KeywordFilter {
return &KeywordFilter{
bannedWords: map[string]bool{"赌博": true, "诈骗": true, "病毒": true},
}
}
func (k *KeywordFilter) SetNext(handler Handler) Handler {
k.next = handler
return handler
}
func (k *KeywordFilter) Handle(request *ContentRequest) error {
for _, kw := range request.Keywords {
if k.bannedWords[kw] {
return fmt.Errorf("关键词 '%s' 被禁止", kw)
}
}
if k.next != nil {
return k.next.Handle(request)
}
return nil
}
描述检查器关注的是摘要部分的信息安全:
go
type DescriptionChecker struct {
next Handler
}
func (d *DescriptionChecker) SetNext(handler Handler) Handler {
d.next = handler
return handler
}
func (d *DescriptionChecker) Handle(request *ContentRequest) error {
if len(request.Description) > 500 {
return fmt.Errorf("描述不能超过500字")
}
if strings.Contains(request.Description, "联系方式") &&
!strings.Contains(request.Description, "官方") {
return fmt.Errorf("非授权联系方式禁止出现在描述中")
}
if d.next != nil {
return d.next.Handle(request)
}
return nil
}
最后是正文分析器,作为链条末端执行最耗时的全文扫描:
go
type BodyAnalyzer struct {
next Handler
}
func (b *BodyAnalyzer) SetNext(handler Handler) Handler {
b.next = handler
return handler
}
func (b *BodyAnalyzer) Handle(request *ContentRequest) error {
if len(request.Body) == 0 {
return fmt.Errorf("正文不能为空")
}
if len(request.Body) > 10000 {
return fmt.Errorf("正文不得超过1万字")
}
// 这里可以接入 NLP 模型或正则规则库
if strings.Contains(request.Body, "破解版") ||
strings.Contains(request.Body, "盗版下载") {
return fmt.Errorf("正文包含侵权内容")
}
return nil // 最后一环无需继续传递
}
构建并使用责任链的过程非常直观:
go
func main() {
request := &ContentRequest{
Title: "Go语言实战技巧",
Keywords: []string{"编程", "开发"},
Description: "分享Golang工程化经验",
Body: "本文介绍如何用Go构建高性能服务...",
}
titleHandler := &TitleValidator{}
keywordHandler := &KeywordFilter{}
descHandler := &DescriptionChecker{}
bodyHandler := &BodyAnalyzer{}
titleHandler.SetNext(keywordHandler).
SetNext(descHandler).
SetNext(bodyHandler)
err := titleHandler.Handle(request)
if err != nil {
log.Printf("内容审核失败: %v", err)
return
}
log.Println("内容审核通过,已发布")
}
这种结构的优势在于高度解耦。新增一种校验逻辑只需实现 Handler 接口,并插入链中适当位置,原有代码无需修改。同时,各处理器职责清晰,测试也更加容易。更重要的是,运行时可根据配置动态组装链条,比如在测试环境中跳过某些耗时检查,或根据不同用户等级启用不同级别的审核策略。
责任链不仅适用于内容审核,还可广泛应用于权限控制、日志处理、API 网关中间件等场景。在 Golang 中结合接口与组合,能够以极少的样板代码实现灵活可靠的请求分发机制。
