把预算上限写进代码,而不是写进自觉

举报
yd_241537561 发表于 2026/10/15 07:36:00 2026/10/15
【摘要】 长时间自动跑的外部请求脚本必须有硬闸门:单主机上限、全天上限、跨天归零、命中即停。这篇记录一个记账文件的结构和四条会让守卫失效的写法。

脚本要每天自己往外发请求,最危险的不是发错,而是「今天已经发了多少」这件事只记在人的脑子里。所以把额度做成代码里的硬约束:一个 JSON 记账文件加四个检查点,超限直接拒发并打印原因。

一、记账结构

// state/budget.json:每发一个包立刻 charge + 落盘,不留批处理的余地
{"day": "2026-10-10", "total": 100,
 "hosts": {"a.example.com": 10, "b.example.com": 15},
 "last": 1791610072.6045036}

def budget_ok(st, host):
    if st["total"] >= MAX_DAY:   return False, "全天已到 %d 上限" % MAX_DAY
    if st["hosts"].get(host, 0) >= MAX_HOST:
        return False, "单主机 %s 已到 %d 上限" % (host, MAX_HOST)
    return True, ""

# 跨天归零:day 不是今天就把整份计数丢掉,而不是去减
if st.get("day") != date.today().isoformat():
    st = {"day": date.today().isoformat(), "total": 0, "hosts": {}, "last": 0}

两个容易忽略的点:一是 charge 之后必须马上 save_state,否则脚本中途崩掉,下一轮又从 0 开始计数;二是跨天要整份归零,按时间衰减的写法在长时间停跑之后会算出负数或半满的幽灵额度。

二、白名单只在最终 URL 的 host 上判一次

如果按「URL 的书写形态」分支放行(带协议的走 A 逻辑、相对的走 B 逻辑),一定会漏。正确做法是解析成最终绝对地址之后,只在 host 上判一次,并且比较时吃点边界:

def inscope(url):
    host = urlparse(url).netloc.split("@")[-1].split(":")[0].lower()
    for d in ALLOWED:                       # d = "example.com"
        if host == d or host.endswith("." + d):
            return True, host
    return False, host                      # 只有整段相等或以 .d 结尾才算

只用 host.endswith(d) 会让 evil-example.com 混进来;顺手再把内网地址(10./172.16-31./192.168.)与保留段拦掉,成本三行。

三、GET 不等于安全

从前端打包产物里扒接口清单时,方法标注是不可信的:确实存在 {method: "get", url: "/api/delRule"} 这种「用 GET 执行删除」的写法。所以判定要叠一层名字语义:删除、绑定、支付、下发验证码、发消息这类写语义的路径,无论标注什么方法都不发。同理,能触发短信/邮件的接口要单独排除,因为它消耗的是真实第三方资源。

四、命中即停,以及「不要有两份守卫」

脚本里除了额度,还要有「出现疑似真数据立刻停」的分支:继续扩面会把一次探测变成一轮扫描。最后一条最工程化:守卫只允许一份实现,其它脚本 from guard import inscope, budget_ok,复制粘贴的第二份守卫一定会和第一份漂移,而漂移的方向通常是放松。

小结

四条失效写法对应四个事故:批处理落盘(崩了就归零)、按形态分支放行(漏 host)、信任方法标注(发出删除)、复制守卫(逻辑漂移)。把上限写进代码之后,「今天别发太多」这件事就不再需要人记得。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。