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

pnp/sp v3.14:如何重新生成令牌并延长请求超时时间?

解决方案

1. 自动刷新请求令牌

请求令牌(Request Digest)默认有效期约30分钟,这是导致超时后403错误的核心原因,可通过两种方式处理:

方式一:循环中定期重置SPFI实例

每处理一定数量的项(比如500个)后,重新初始化SPFI实例,自动获取新的请求令牌:

for(let i=0;i<item_data_id.length;i++)
{
  // 每处理500项刷新一次令牌
  if (i % 500 === 0) {
    sp2 = spfi().using(SPBrowser({ baseUrl: props.context.pageContext.web.absoluteUrl })).using(RequestDigest());
  }
  id = item_data_id[i].id;
  per = item_data_id[i].permissions;
  await assignPermissionsbyID(id, per, roleDefId, froleDefId, current_user, sp2);
}

方式二:自定义令牌自动刷新逻辑

封装RequestDigest行为,添加过期检查,每次请求前自动刷新即将过期的令牌:

import { spfi, SPBrowser, RequestDigest, IRequestDigestInfo } from "@pnp/sp";

class AutoRefreshDigest {
  private digest: IRequestDigestInfo | null = null;

  async getValidDigest(sp: any): Promise<IRequestDigestInfo> {
    // 提前5分钟刷新令牌,避免过期
    const now = Date.now();
    if (!this.digest || now > (this.digest.expiration - 5 * 60 * 1000)) {
      this.digest = await RequestDigest().getDigest(sp);
    }
    return this.digest;
  }
}

// 创建带自动刷新令牌的SPFI实例
const sp2 = spfi().using(SPBrowser({ baseUrl: props.context.pageContext.web.absoluteUrl }))
  .using({
    async fetch(url: string, options: any, sp: any) {
      const validDigest = await new AutoRefreshDigest().getValidDigest(sp);
      options.headers = {
        ...options.headers,
        "X-RequestDigest": validDigest.value,
      };
      return fetch(url, options);
    },
  });

2. 延长请求超时时间

pnp/sp v3.x可通过自定义fetch行为,结合AbortController实现全局或单个请求的超时设置:

方式一:全局设置超时

为SPFI实例添加全局超时逻辑,所有请求统一应用超时时间:

const sp2 = spfi().using(SPBrowser({ baseUrl: props.context.pageContext.web.absoluteUrl }))
  .using(RequestDigest())
  .using({
    async fetch(url: string, options: any) {
      const controller = new AbortController();
      // 设置2分钟超时,可根据需求调整
      const timeoutId = setTimeout(() => controller.abort(), 120000);
      try {
        const response = await fetch(url, {
          ...options,
          signal: controller.signal,
        });
        clearTimeout(timeoutId);
        return response;
      } catch (e) {
        clearTimeout(timeoutId);
        throw e;
      }
    },
  });

方式二:单个请求设置超时

针对耗时较长的单个请求单独设置超时,比如在权限分配方法中:

async function assignPermissionsbyID(id:number,permission_ids:Array<number>,roleDefId:number,froleDefId:number,current_user: ISiteUserInfo,sp:SPFI):Promise<void>
{
  const list_id=props.list_id.trim();
  const list = await sp.web.lists.getByTitle(list_id);
  
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 60000); // 1分钟超时
  try {
    await list.items.getById(id).breakRoleInheritance(false, {
      signal: controller.signal, // 传递超时信号
    });
  } finally {
    clearTimeout(timeoutId);
  }

  // 其他权限操作同理...
}

额外优化建议

  • 批量操作减少请求次数:使用pnp/sp的Batch功能,将单个项的多个权限操作合并为一个批量请求,降低API调用频率,减少令牌消耗。
  • 添加403重试逻辑:捕获403错误后,刷新令牌并重试当前操作,提升稳定性。

内容的提问来源于stack exchange,提问作者Zeeshan Fakhar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 22:07:04