0

0

如何在 Token 过期后从中断位置恢复 JSON 迭代任务

心靈之曲

心靈之曲

发布时间:2026-02-08 10:40:51

|

648人浏览过

|

来源于php中文网

原创

如何在 Token 过期后从中断位置恢复 JSON 迭代任务

本文介绍一种健壮的断点续传机制:当调用 api 过程中因 token 失效中断时,自动记录最后失败的 clientid,并在下次运行时从此处继续迭代,避免重复请求和数据丢失

在批量处理 JSON 数据并逐个调用外部 API 的场景中(如按 ClientId 查询客户信息),Token 有效期限制常导致任务中途失败。若每次失败后都从头重跑,不仅浪费资源、延长执行时间,还可能引发接口限流或数据重复写入等问题。理想的解决方案是实现可持久化状态的断点续传——即准确记住上一次中断的位置,并精准恢复。

核心设计思路

我们不依赖内存中的索引变量(易丢失),而是采用外部状态文件(如 last_failed.txt)持久化记录最后一次失败的 ClientId。程序启动时优先检查该文件:

  • 若文件不存在 → 从第一个 Client 开始遍历;
  • 若文件存在 → 从文件中记录的 ClientId 开始(含) 继续遍历,跳过此前已成功处理的部分。

该策略的关键在于:“从指定 ClientId 恢复” ≠ “跳过该 Client”,而是包含它——因为上一次正是在此 Client 触发了 Token 过期,需重新尝试该请求。

快剪辑
快剪辑

国内⼀体化视频⽣产平台

下载

实现要点与代码详解

以下是一个生产就绪的参考实现(已适配原 JSON 结构):

import json
import pathlib
import requests
import time

# ✅ 配置项:请根据实际环境修改
API_BASE_URL = "https://api.example.com/clients/"  # 示例 URL 模板
AUTH_TOKEN = "your_bearer_token_here"
LAST_FAILED_PATH = pathlib.Path("last_failed.txt")

def load_clients_from_json(filepath: str):
    """安全加载并扁平化解析 ClientList 数组"""
    with open(filepath, encoding="utf-8") as f:
        data = json.load(f)
    clients = []
    for item in data:
        if "ClientList" in item and isinstance(item["ClientList"], list):
            clients.extend(item["ClientList"])
    return clients

def find_client_start_index(clients: list, target_id: str) -> int:
    """线性查找目标 ClientId 的索引(支持重复 ID 场景)"""
    for i, client in enumerate(clients):
        if client.get("ClientId") == target_id:
            return i
    raise ValueError(f"ClientId '{target_id}' not found in client list")

def call_api_with_retry(client: dict) -> tuple[bool, str]:
    """封装 API 调用逻辑,返回 (是否成功, 响应文本/错误信息)"""
    url = f"{API_BASE_URL}{client['ClientId']}"
    headers = {
        "Authorization": f"Bearer {AUTH_TOKEN}",
        "Cache-Control": "no-cache",
    }

    try:
        response = requests.get(url, headers=headers, timeout=30)

        if response.status_code == 200:
            return True, response.text
        elif response.status_code == 401 or response.status_code == 403:
            # ⚠️ 典型 Token 过期响应码(依实际 API 调整)
            err_data = response.json()
            if "expired" in err_data.get("message", "").lower() or "invalid token" in err_data.get("error", "").lower():
                return False, "Token expired"
        # 其他错误(如 500、404)视为业务失败,不中断流程
        return False, f"HTTP {response.status_code}: {response.text[:200]}"

    except requests.exceptions.RequestException as e:
        return False, f"Request failed: {str(e)}"
    except json.JSONDecodeError:
        return False, f"Invalid JSON response: {response.text[:200]}"

def main():
    # Step 1: 加载所有客户端数据
    clients = load_clients_from_json("client_file.json")
    if not clients:
        print("⚠️  Warning: No clients found in JSON file.")
        return

    # Step 2: 确定起始位置
    start_idx = 0
    if LAST_FAILED_PATH.exists():
        try:
            with open(LAST_FAILED_PATH) as f:
                last_id = f.read().strip()
            start_idx = find_client_start_index(clients, last_id)
            print(f"▶️  Resuming from ClientId: {last_id} (index {start_idx})")
        except (ValueError, FileNotFoundError) as e:
            print(f"⚠️  Failed to resume: {e}. Starting from beginning.")
            LAST_FAILED_PATH.unlink(missing_ok=True)

    # Step 3: 迭代调用 API
    success_count = 0
    failed_count = 0
    start_time = time.time()

    for i in range(start_idx, len(clients)):
        client = clients[i]
        client_id = client.get("ClientId", "N/A")
        print(f"\n? Processing ClientId: {client_id}")

        is_success, result = call_api_with_retry(client)

        if is_success:
            success_count += 1
            print(f"✅ Success | Response length: {len(result)} chars")
        else:
            failed_count += 1
            print(f"❌ Failed | Reason: {result}")

            # ? 关键:仅当 Token 过期时才保存断点并退出
            if "Token expired" in result:
                print(f"? Token expired at ClientId '{client_id}'. Saving checkpoint...")
                with open(LAST_FAILED_PATH, "w") as f:
                    f.write(client_id)
                print("⏹️  Execution paused. Rerun script to resume.")
                break
    else:
        # ✅ 正常完成全部迭代:清除断点文件
        if LAST_FAILED_PATH.exists():
            LAST_FAILED_PATH.unlink()
            print("✅ All clients processed successfully. Checkpoint cleared.")

    # Step 4: 输出统计摘要
    elapsed = time.time() - start_time
    print(f"\n? Summary: {success_count} success, {failed_count} failed | Time: {elapsed:.2f}s")

if __name__ == "__main__":
    main()

注意事项与最佳实践

  • Token 过期判定要精准:不同 API 返回的过期标识各异(如 401 Unauthorized、{"error":"invalid_token"}、"Session expired")。务必根据实际响应调整 call_api_with_retry() 中的判断逻辑,避免误判导致意外中断。
  • 状态文件路径需可写:确保脚本对 last_failed.txt 所在目录有读写权限;生产环境建议使用绝对路径或配置化存储位置。
  • 幂等性保障:API 设计应支持重复请求(如 GET 查询类接口天然幂等)。若为 POST/PUT 类操作,请在服务端增加幂等 Key 或客户端做去重校验。
  • 异常兜底:示例中对 JSON 解析失败、网络超时等做了基础捕获。在关键业务中,建议增加日志框架(如 logging)记录详细上下文,并接入告警。
  • 性能优化(可选):若 ClientList 极大(数万+),可将 find_client_start_index 替换为哈希映射预构建索引,加速定位。

总结

通过引入轻量级外部状态文件 + 清晰的起始索引定位逻辑,我们实现了稳定、可预测的断点续传能力。该方案无需数据库、不依赖外部服务,兼容性强,且易于集成到定时任务(如 cron)或 CI/CD 流水线中。记住核心原则:失败即存档,启动先检查,恢复即重试——让批量 API 调用真正具备韧性与可维护性。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

431

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

542

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

314

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

79

2025.09.10

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

321

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

764

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

95

2025.08.19

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

331

2023.10.18

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

39

2026.02.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.9万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号