登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go问答

Go strconv.Atoi溢出返回错误时的输入校验顺序

来源:17golang原创

时间:2026-09-20 15:27:47 137浏览 收藏

处理 URL 参数、表单字段或配置文本时,strconv.Atoi 的两个返回值必须一起看。正确顺序是:先判断 err,再做业务允许范围检查,最后才把 int 交给计算、查询或写入逻辑。溢出时返回的数值不能当成可信输入,不能因为它“看起来接近”就继续使用。

要点速览
  • Atoi 按当前平台的 int 宽度解析十进制字符串,语法错误和范围错误都通过 error 暴露。
  • 错误判断要早于日志拼接、范围比较和下游调用,避免把零值或不完整结果当成正常值。
  • 通过解析层、业务范围层、使用层三道边界,能把可审计的拒绝原因留在入口。
Go strconv.Atoi 从外部字符串到 int 和 error 的静态输入闸门说明图
图1:Go strconv.Atoi 的输入、解析结果和 error 边界说明图,不是运行截图。

先把 Atoi 的返回值和错误绑定为一个输入闸门

Atoi 等价于以十进制、位宽 0 调用 ParseInt,再转换成 int。位宽 0 代表使用当前平台的 int 宽度,所以同一串数字在不同运行环境中可能触发不同的范围边界。对来自网络或用户的输入,不能先使用 value 再补查错误。

package main

import (
	"fmt"
	"strconv"
)

func parsePageSize(raw string) (int, error) {
	// 先解析并检查 error;失败时不让 value 进入业务路径。
	value, err := strconv.Atoi(raw)
	if err != nil {
		return 0, fmt.Errorf("page size %q is not a valid int: %w", raw, err)
	}
	// 解析成功只说明它能表示为 int,还要满足业务允许范围。
	if value  100 {
		return 0, fmt.Errorf("page size %d is outside 1..100", value)
	}
	return value, nil
}

这里返回的 0 是失败分支的占位值,不是“解析失败后的可用结果”。调用方应以 err == nil 作为进入后续逻辑的唯一条件,而不是只判断 value == 0

区分语法错误、范围错误与业务范围拒绝

输入 "12x" 属于语法问题,输入一个超过当前 int 宽度的十进制数字属于范围问题;即使输入是合法整数,例如 1000,也可能因为页面大小只允许 1 到 100 而被业务层拒绝。三类失败的处理者和审计信息不同,不建议统统返回“参数错误”。

阶段判断处理重点
解析err != nil拒绝语法错误或 ErrRange,记录字段名与脱敏后的原始值
业务范围value max说明允许区间,避免下游重复猜测规则
使用只有前两层通过进入分页、索引或计算逻辑,保留请求关联信息

如果需要区分标准库给出的原因,可以用 errors.Is 检查 strconv.ErrRangestrconv.ErrSyntax;日志中保存稳定的错误类别比直接依赖完整错误字符串更适合统计。

Go Atoi 语法错误、整数溢出和业务范围拒绝三层边界关系说明图
图2:从解析错误到业务拒绝的三层边界结构说明图,不是运行结果截图。

把校验顺序固定在解析、范围、使用三道边界

安全威胁建模时,外部数字字符串是输入资产,后续查询和资源分配是受保护的业务动作。最常见的风险不是 Atoi 会“静默截断”,而是代码忽略 err 后继续拿返回值参与判断,或者在多个调用点各写一套不一致的上下限。

func handleLimit(raw string) error {
	limit, err := strconv.Atoi(raw)
	if err != nil {
		// 先记录稳定类别,再返回对外统一的参数错误。
		if errors.Is(err, strconv.ErrRange) {
			return fmt.Errorf("limit is out of int range: %w", err)
		}
		return fmt.Errorf("limit has invalid syntax: %w", err)
	}
	if limit  1000 {
		// 业务范围失败不能伪装成解析成功。
		return fmt.Errorf("limit must be between 1 and 1000")
	}
	// 只有通过两层检查的值才交给昂贵或有副作用的操作。
	return reserveResources(limit)
}

生产代码还应统一处理负号、前导空格、空字符串和极大数字。Atoi 不等于“清洗输入”:如果产品允许空格,应在明确的入口策略中处理;如果不允许,就让原始解析错误可追踪地返回。

用检查清单确认下游拿到的确实是可信 int

  • 是否在第一次使用返回值前检查了 err
  • 是否将标准库可识别的范围错误与业务上下限拒绝分开?
  • 是否用一个入口函数集中定义上下限,避免分页、批量和超时参数各自漂移?
  • 是否覆盖空字符串、非数字、负数、边界值和超过 int 范围的数字?

测试时至少准备一组刚好等于最小值、最大值的样例,以及一个比 int 最大值更长的十进制字符串。这样才能证明代码检查的是错误状态,而不是碰巧检查到了某个零值。

相关问题

Atoi 溢出后返回的 int 能不能继续使用?

不能。只要 err != nil,返回值就不应进入业务计算、查询参数或资源分配流程。

什么时候应该改用 ParseInt?

当接口协议要求固定的 32 位或 64 位整数,或者需要明确指定进制和位宽时,使用 ParseInt 更直接;不要让平台位宽替你决定协议边界。

只判断数值是否为零可以代替检查 error 吗?

不可以。合法输入也可能是零,错误返回值也不应被当成正常数值;错误状态必须显式判断。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>