静默监控的工程实践:Cookie 鉴权、动态 CSRF 与「只在变化时通知」的设计

举报
yd_253728243 发表于 2026/10/13 18:29:58 2026/10/13
【摘要】 前言 很多同学做"监控/签到/采集"这类自动化时,第一版往往是「定时跑一次,把结果推给我」。跑上几天就会发现两个问题:一是告警疲劳(没变化也一直在推,最后你会把通知关掉);二是跑了一段时间突然失效(Cookie 或 CSRF 令牌过期,脚本静默失败,你却不知道)。 本文把我在一台 NAS 上做的长期静默监控实践中踩到的坑和最终结构整理出来,涉及 Cookie 鉴权、动态 CSRF、调度粒度和...

前言

很多同学做"监控/签到/采集"这类自动化时,第一版往往是「定时跑一次,把结果推给我」。跑上几天就会发现两个问题:一是告警疲劳(没变化也一直在推,最后你会把通知关掉);二是跑了一段时间突然失效(Cookie 或 CSRF 令牌过期,脚本静默失败,你却不知道)。

本文把我在一台 NAS 上做的长期静默监控实践中踩到的坑和最终结构整理出来,涉及 Cookie 鉴权、动态 CSRF、调度粒度和"只推变化"的通知设计。所有代码片段都是真实在跑的简化版(Python 3,只用标准库)。

一、先说结论:什么叫"静默监控"

  • 无变化 = 不通知。只有状态真的变了才发消息,这是让通知活得久的前提。
  • 失败了要吵。反过来,鉴权失效/接口异常必须主动报警,否则你会以为"一切正常"。
  • 告警要分优先级,并且明确"什么不推"。例如库存监控里,"取消订单退回 1 件"这种噪音就不该推。

实现上就是一句话:保存上一次的快照,每次拉取后做 diff。

prev = state.get("goods") or {}
cur  = {g["id"]: normalize(g) for g in fetch()}
if not prev:
    save(cur)          # 首次只建基线,不通知
else:
    changes = diff(cur, prev)
    if changes:
        notify(changes)   # 有变化才推
    save(cur)

二、鉴权:Cookie 的坑,90% 的人第一步就错

抓包抄 Cookie 是最常见的做法,但有个细节几乎人人都踩:

❌ 只抄 document.cookie 或用 Cookie 导出插件 → 一定失败。
✅ 从 DevTools 的 Network 面板里,复制某个请求的 Cookie: 请求头,或者直接 Copy as cURL。

原因是登录令牌通常是 HttpOnly 的,JS 读不到,导出插件默认也不导。症状很有迷惑性:你明明在浏览器里登录着,脚本却一直返回"未登录"。

经验的判别方式:如果服务端返回 401/403 not login,而你的 Cookie 串里找不到类似 SID、xxx_token、session 这类明显的会话项,基本就是这个原因。

三、CSRF:令牌会过期,必须动态取

很多系统(尤其是背后有网关的平台)除了 Cookie,还要求一个 CSRF 令牌放在请求头里。关键点是:这个令牌有寿命,通常几十分钟。写死一个值,脚本跑一会儿就会开始 403。

典型表现:

# 不带令牌
403 {"message":"no request_csrf found"}
# 带了过期的令牌
403 {"message":"CSRF is nil"}

正确做法是每次请求前确保令牌新鲜,并且失败时能自动刷新重试一次:

_CSRF_CACHE = {}

def get_csrf(cookie, refresh=False):
    if not refresh and _CSRF_CACHE.get(cookie[-40:]):
        return _CSRF_CACHE[cookie[-40:]]
    # 令牌由专门的接口通过「响应头」下发
    r = urllib.request.Request(CSRF_URL, headers={"Cookie": cookie})
    with urllib.request.urlopen(r, timeout=20) as resp:
        tok = resp.headers.get("csrf")      # ← 注意是响应头
    if tok:
        _CSRF_CACHE[cookie[-40:]] = tok
        return tok

def request(url, body=None, _retry=True):
    headers = {"Cookie": cookie, "csrf": get_csrf(cookie),
               "Content-Type": "application/json"}
    try:
        ...  # 正常请求
    except urllib.error.HTTPError as e:
        text = e.read().decode()
        if _retry and "csrf" in text.lower():        # 令牌过期 → 刷新重试一次
            get_csrf(cookie, refresh=True)
            return request(url, body, _retry=False)
        raise

注意:令牌往往不在 Cookie 里,而是某个接口的响应头里(本文这套是 GET /api/get-ainfo 返回的 csrf 响应头)。所以别拿 Cookie 里名字很像的那个值去凑。

四、调度粒度:cron 最小 1 分钟,但你需要 5 秒

想要"更快的响应",用 cron 是压不下去的(最小粒度 1 分钟)。一个简单可靠的折中是:cron 每分钟拉起一次,脚本在自己的进程里做高频轮询,跑满约 50 秒后退出。

# cron: * * * * *
POLL_INTERVAL = 5      # 轮内每 5 秒探一次
RUN_SECONDS   = 55     # 单次运行时长,留出空隙交给下一次 cron

deadline = time.time() + RUN_SECONDS
while time.time() < deadline:
    t0 = time.time()
    try:
        poll_once()                      # 一次内只发 1 个请求
    except Exception as e:
        log("本轮异常", e)                # 单轮失败不影响后续
    sleep = POLL_INTERVAL - (time.time() - t0)
    if time.time() + max(sleep, 0) >= deadline:
        break
    time.sleep(max(sleep, 0))

两个必须配的护栏:

  • 文件锁防重叠:万一某轮耗时超过 60 秒,下一次 cron 已经在路上了,没有锁就会出现两个进程同时跑、状态互相覆盖。
  • 退避重试:被限流(429/503)时不要死磕,指数退避。
LOCK = os.path.join(HERE, ".monitor.lock")
fd = os.open(LOCK, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
# ... finally: os.close(fd); os.unlink(LOCK)

五、把"有用信息"放进通知里

通知只推变化还不够,内容也要直接可用。以库存监控为例,每条消息里都带上:当前是否可购买、价格、总量/已售/剩余、以及一张"当前可购买清单"。这样用户扫一眼就能决策,不用再打开 App 查。

另外建议把关键账号状态一并带上(比如积分余额、剩余可用次数),因为这类自动化最终往往要落到"能不能真的执行一次"上。

六、一个反面提醒:别为了跑通而绕过平台规则

实践中经常遇到"只差一个身份/权限"的情况。此时如果想的是"找接口把这个身份开出来",那就越界了:这类接口通常是给演示/测试账号用的,用它给你的真实账号开权限,风险是账号被处置。

能做的是把链路摸清、把代价讲明,然后把选择权交回给人。技术上的"可做"和"该做"是两件事。

七、小结 Checklist

  • Cookie 从 Network → 请求头 或 Copy as cURL 取,别用导出插件(HttpOnly)。
  • CSRF/签名类令牌动态获取,缓存 + 过期自动刷新重试。
  • 快照 + diff 决定"推不推",无变化一律静默。
  • 鉴权失效、接口异常必须报警(这类"静默失败"最致命)。
  • 调度用"cron 每分钟拉起 + 进程内高频轮询",配文件锁与退避。
  • 不在通知里堆原始数据,直接给结论与可执行信息。

把这几点做到,一个自动化脚本从"能跑"到"能长期跑",差距基本就在这里。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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