You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GoFiber+AWS SAM本地API:OpenAI审核标记后代码仍执行问题

GoFiber中调用审核函数后代码仍继续执行的问题修复

问题背景

使用GoFiber结合AWS API Gateway开发API,通过sam local start-api本地测试。API在执行OpenAI生成文本/图像的核心逻辑前,会调用ModeratePromptInput函数检查用户输入。当前问题是:当审核函数理应返回错误时,调用处的err != nil判断无法终止后续代码执行,程序仍会继续走核心逻辑流程。

调用处关键代码

// 函数签名:
// func GenerateOutput(c *fiber.Ctx) (interface{}, error) 

// ....
// 创建OpenAI客户端用于依赖注入
oClient := openai.NewClient(os.Getenv("OPENAI_SECRET_KEY"))

// 审核输入以防止滥用(若输入违规则提前退出)
err := actions.ModeratePromptInput(c, oClient)
if err != nil {
    log.Printf("Error moderating prompt input: %v", err)
    return nil, c.JSON(fiber.Map{
        "error": "Error within error logic",
    })
}
// 此处代码仍会执行 - 希望出错时终止

审核函数代码

func ModeratePromptInput(c *fiber.Ctx, oClient *openai.Client) error {
    promptInput := models.NewOutputRequest{}
    if err := c.BodyParser(&promptInput); err != nil {
        return err
    }

    moderationInput := openai.ModerationRequest{}
    moderationInput.Input = promptInput.UserInput

    res, err := oClient.Moderations(c.Context(), moderationInput)
    if err != nil || res.Results == nil || len(res.Results) == 0 {
        return c.Status(500).JSON(fiber.Map{
            "error": "Could not moderate input",
        })
    }

    if res.Results[0].Flagged {
        return c.Status(403).JSON(fiber.Map{
            "error":    "Input is abusive",
            "results:": res.Results,
        })
    }
    return nil
}

问题根源

核心原因是Fiber的c.Status().JSON()方法返回值为nil:
该方法的作用是向客户端发送HTTP响应,其返回的error类型值仅在响应发送失败时才会是非nil,成功发送响应时始终返回nil。这就导致你在ModeratePromptInput中返回c.Status(500).JSON(...)或c.Status(403).JSON(...)时,调用处拿到的err实际是nil,自然不会进入错误分支,后续代码会继续执行。

修复方案

方案1:分离错误逻辑与响应发送(推荐)

让审核函数仅负责业务逻辑判断,返回具体错误信息,由调用处统一处理响应发送,保持职责单一。

步骤1:定义自定义错误类型

在models包中定义用于传递审核错误的自定义类型:

package models

import "github.com/sashabaranov/go-openai"

type ModerationError struct {
    Message string
    Results []openai.ModerationResult
    StatusCode int
}

func (e *ModerationError) Error() string {
    return e.Message
}

步骤2:修改审核函数

去掉函数内的响应发送逻辑,返回自定义错误或标准错误:

func ModeratePromptInput(c *fiber.Ctx, oClient *openai.Client) error {
    promptInput := models.NewOutputRequest{}
    if err := c.BodyParser(&promptInput); err != nil {
        return &models.ModerationError{
            Message:    "Failed to parse input",
            StatusCode: 400,
        }
    }

    moderationInput := openai.ModerationRequest{}
    moderationInput.Input = promptInput.UserInput

    res, err := oClient.Moderations(c.Context(), moderationInput)
    if err != nil || res.Results == nil || len(res.Results) == 0 {
        return &models.ModerationError{
            Message:    "Could not moderate input",
            StatusCode: 500,
        }
    }

    if res.Results[0].Flagged {
        return &models.ModerationError{
            Message:    "Input is abusive",
            Results:    res.Results,
            StatusCode: 403,
        }
    }
    return nil
}

步骤3:修改调用处逻辑

通过错误类型断言处理不同的错误场景:

err := actions.ModeratePromptInput(c, oClient)
if err != nil {
    log.Printf("Error moderating prompt input: %v", err)
    
    var modErr *models.ModerationError
    if errors.As(err, &modErr) {
        // 处理审核相关错误,发送对应响应
        response := fiber.Map{"error": modErr.Message}
        if modErr.Results != nil {
            response["results"] = modErr.Results
        }
        return nil, c.Status(modErr.StatusCode).JSON(response)
    }
    
    // 处理其他未知错误
    return nil, c.Status(500).JSON(fiber.Map{
        "error": err.Error(),
    })
}
// 后续核心逻辑仅在无错误时执行

方案2:简化的哨兵错误方案

如果不想定义自定义错误,可以在审核函数中发送响应后,返回一个非nil的哨兵错误,确保调用处能进入错误分支:

步骤1:定义哨兵错误

var ErrModerationFailed = errors.New("moderation process failed")

步骤2:修改审核函数

发送响应后返回哨兵错误:

func ModeratePromptInput(c *fiber.Ctx, oClient *openai.Client) error {
    promptInput := models.NewOutputRequest{}
    if err := c.BodyParser(&promptInput); err != nil {
        c.Status(400).JSON(fiber.Map{"error": "Failed to parse input"})
        return ErrModerationFailed
    }

    moderationInput := openai.ModerationRequest{}
    moderationInput.Input = promptInput.UserInput

    res, err := oClient.Moderations(c.Context(), moderationInput)
    if err != nil || res.Results == nil || len(res.Results) == 0 {
        c.Status(500).JSON(fiber.Map{"error": "Could not moderate input"})
        return ErrModerationFailed
    }

    if res.Results[0].Flagged {
        c.Status(403).JSON(fiber.Map{
            "error":    "Input is abusive",
            "results":  res.Results,
        })
        return ErrModerationFailed
    }
    return nil
}

步骤3:修改调用处逻辑

因为审核函数已经发送了响应,调用处只需直接返回即可:

err := actions.ModeratePromptInput(c, oClient)
if err != nil {
    log.Printf("Error moderating prompt input: %v", err)
    // 响应已在审核函数中发送,直接返回终止流程
    return nil, nil
}
// 后续核心逻辑仅在无错误时执行

总结

问题本质是对Fiber响应方法的返回值理解偏差,解决核心是确保审核函数在需要终止流程时,返回非nil的错误值,让调用处的err != nil判断生效。方案1更符合Go的错误处理最佳实践,便于后续扩展;方案2则更简洁,适合简单场景。

内容的提问来源于stack exchange,提问作者Joel Hager

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 09:14:59