@b-jones-rfd/sp-rest-connect

中文文档
5.1.1发布于 2026/10/11MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 2036

使用 SharePoint REST 服务与列表和文档库交互

中文使用文档
文档目录30 节
  1. 所需资源
  2. 认证
  3. 安装
  4. 快开始
  5. 使用量
  6. 站点连接
  7. 独立行动
  8. 结果
  9. 写入操作:请求摘要
  10. 创建和更新项目
  11. 大型文件
  12. 文件夹
  13. 打字结果
  14. 拨号
  15. 重试瞬间失败
  16. CAML 查询和 5000 项阈值
  17. 请求
  18. 共同选项
  19. TLS 和内部证书
  20. 特殊字符
  21. API 密码
  22. 名单
  23. 文件库
  24. 击打
  25. 认证
  26. 错误
  27. 迁移到 5.0
  28. 捐款
  29. 版本
  30. 许可证

CI npm version npm unpacked size node code style: prettier

SharePoint REST 连接

一个小型、无依赖的节点客户端 默认共享点 资源 服务,带有内置的NTLMv2认证. 读取和写入列表项目, 上传并下载文档,管理文件夹. 每次呼叫返回一个输入 Result 而不是扔东西.

我厌倦了为工作项目重写这些.

所需资源

  • 节点.js 20或后.
  • 内置共享点 ——2013,2016,2019或订阅版-与 NTLM 认证启用 。 共享点在线是 没有 支持; 确实 不接受 NTLM.
  • 没有别的事了 没有运行时间依赖性: NTLM 在顶端执行 联 合 国 node:http编号 :node:https 财务报告和审定财务报表 node:crypto。 。 。 .

认证

仅 NTLMv2 地图 支持。 SharePoint 2013 并随后通过谈判 默认。 如果服务器没有发送NTLMv2要求的目标信息, 请求失败 NTLM server did not send target info 而不是沉默无声 降级为 NTLMv1, 在 Node 的 OpenSSL 3 中不安全且不可用 建设.

安装

npm i @b-jones-rfd/sp-rest-connect
# or
pnpm add @b-jones-rfd/sp-rest-connect
# or
yarn add @b-jones-rfd/sp-rest-connect

快开始

import { createSiteConnection } from '@b-jones-rfd/sp-rest-connect'

const connection = createSiteConnection({
  username: 'jsmith',
  password: process.env.SP_PASSWORD!,
  domain: 'CONTOSO', // NTLM (NetBIOS) domain, not a DNS name
  site: 'sharepoint.contoso.local',
  serverRelativeUrl: '/sites/finance',
})

// Read
type Invoice = { Id: number; Title: string; Amount: number }
const params = new URLSearchParams({ $select: 'Id,Title,Amount', $top: '500' })
const items = await connection.getAllListContents<Invoice>({
  listName: 'Invoices',
  params,
})
if (!items.success) throw new Error(items.error)
console.log(items.data.map((i) => i.Title))

// Write: the request digest and the list's entity type are handled for you
const created = await connection.addListItem({
  listName: 'Invoices',
  payload: { Title: 'INV-1042', Amount: 1250 },
})
if (created.success) console.log(created.data.Id)

更多实例包括文档上传 examples/basic.ts。 。 。 .

使用量

站点连接

createSiteConnection(options) 将每个动作绑在一个站点并返回 a SiteConnection。创建连接不执行网络 I/O; 证书 在封锁中被俘获,并用于每次呼叫。 它确实检查了形状 选项并丢出 TypeError 对于明显错误( 内部协议) site页:1 serverRelativeUrl 没有领先的斜线,所以错位 启动时失败, 而不是后来的不透明 404 .

选项类型需求默认说明
usernamestringYWindows账户名称,没有域名.
passwordstringY账户密码。 从环境读取,而不是硬编码.
sitestringY只使用主机名称, 例如 . 'sharepoint.contoso.local'。 。 。 .
serverRelativeUrlstringY站点(web)路径,例如:. '/sites/finance'全部数据 folder 参数将据此解决.
protocol'https' | 'http'无'https'
domainstring无''NTLM (NetBIOS) 域名, 如. 'CONTOSO'。为服务器本地账户留空.
hostnamestring无os.hostname()工作站名传入NTLM握手. 很少需要改变.
agentOptionshttps.AgentOptions无HTTP 代理的 TLS / socket 选项 。 见 TLS 和内部证书。 。 。 .
retryRetryOptions无重试读取动作上的瞬态失败 。 见 重试瞬间失败。 。 。 .

独立行动

单用或只导入您需要的东西, 每个动作都会导出 作为工厂。 用相同的选项调用它以获得可重复使用的动作 :

import { getListContents } from '@b-jones-rfd/sp-rest-connect'

const fetchList = getListContents(siteConnectionOptions)
const items = await fetchList({ listName: 'Invoices' })

结果

每个行动都决定 Result<T> 绝不扔出:

type Result<T> = Success<T> | Failure

type Success<T> = { success: true; data: T }
type Failure = {
  success: false
  error: string // "Error in getListContents: HTTP 404: List 'Tasks' does not exist"
  code: FailureCode
  status?: number // HTTP status, for HTTP / AUTH failures
  details?: { code?: string; message?: string } // SharePoint's own error, when it sent one
  retryAfterMs?: number // from a Retry-After header, when present
}

检查 success 缩小,然后在 code 而不是在留言上 文本 :

code含义
HTTPSharePoint以非-2xx状态(401/403除外)回答. 见 status编号 :details。 。 。 .
AUTH401或403——不良资质,NTLM被否决,或缺失/过期请求文摘.
TIMEOUT没有到达字节 timeout m.
ABORTED取消通过 signal。 。 。 .
NETWORKDNS,连接或TLS在任何响应前失败.
PARSE2xx反应,其身体未达到预期状态.
UNKNOWN任何别的事.
const res = await connection.addListItem({ listName, payload })
if (!res.success) {
  if (res.code === 'AUTH') await alertOps('credentials rejected')
  else if (res.code === 'TIMEOUT' || res.code === 'NETWORK') await retryLater()
  else log.error(res.error, res.details)
}

error 总是以动作名称为前缀的人类可读信件,用于 伐木业.

写入操作:请求摘要

SharePoint 需要一个 X-RequestDigest 每封信都写着标题 连接 处理好它:第一封信从 /_api/contextinfo, (中文(简体) ), 缓存到SharePoint说它过期前一分钟(30分钟后) 如果SharePoint仍以403拒绝,则摘要会被刷新 并重审过一次 同步写入共享一个获取 .

自己管理消化器,通过 requestDigest 明确——缓存是 然后绕行,不发生自动重试. getFormDigestValue() 获取 一个.

独立行动工厂各自保存自己的缓存. 分享一个,创建一个 上下文并当作第二个论点:

import {
  createConnectionContext,
  addListItem,
  deleteListItem,
} from '@b-jones-rfd/sp-rest-connect'

const ctx = createConnectionContext(options)
const add = addListItem(options, ctx)
const remove = deleteListItem(options, ctx) // shares add's digest

getAuthToken() 实值 没有 这个值——它返回NTLM握手头, 这是连接的,并且只是用作证书检查.

创建和更新项目

addListItem 财务报告和审定财务报表 updateListItem 取一个普通对象。 共享点需要 列表的实体类型( n)__metadata.type)在身体上;连接在上看 与 getListItemType 它第一次看到列表并缓存它:

await connection.addListItem({
  listName: 'Invoices',
  payload: { Title: 'INV-1042', Amount: 1250 },
})

await connection.updateListItem({
  listName: 'Invoices',
  spId: 17,
  patch: { Amount: 1300 },
})

包含 __metadata: { type: 'SP.Data.InvoicesListItem' } 在对象中 你自己跳过检查. addListItem 确定创建的项目为 SharePoint 将它带回了新 Id; 通过其它参数的类型 形状addListItem<Invoice>(...)) (中文(简体) ).

updateListItem 是部分更新( OData) MERGE 与 If-Match: *: 仅限 输入 patch 更改,最后的作者获胜.

大型文件

addDocumentToLibrary 接受一个 Readable 作为 payload,以及 getDocumentStreamFromLibrary 返回一个,所以文件从不需要适应 内存 :

import { createReadStream, createWriteStream } from 'node:fs'
import { stat } from 'node:fs/promises'
import { pipeline } from 'node:stream/promises'

const { size } = await stat('backup.zip')
await connection.addDocumentToLibrary({
  folder: 'Shared Documents/Archive',
  fileName: 'backup.zip',
  payload: createReadStream('backup.zip'),
  contentLength: size, // optional; without it the upload is chunked
})

const download = await connection.getDocumentStreamFromLibrary({
  folder: 'Shared Documents/Archive',
  fileName: 'backup.zip',
})
if (download.success)
  await pipeline(download.data, createWriteStream('restored.zip'))

只能发送一次流, 所以如果管理中的文摘显示为呆滞 中上载写入代码失败 AUTH 而不是再审;拨打 再来一次 下载时的 HTTP 错误报告为 Failure 在任何时间之前 溪流返回.

文件夹

每个 folder 参数相对 serverRelativeUrl 然后从 库名称 : 'Shared Documents', (中文(简体) ), 'Shared Documents/Reports/2026'。 。 。 .

打字结果

getListContents, (中文(简体) ), getFolderContents 财务报告和审定财务报表 getListItem 选择类型参数 用于项目形状。 这是一种断言,而不是验证 但它在每一个呼叫站点都省下一个铸造者:

type Task = { Id: number; Title: string; Status: 'Open' | 'Done' }

const res = await connection.getListContents<Task>({
  listName: 'Tasks',
  params,
})
if (res.success) res.data.filter((t) => t.Status === 'Open')

拨号

最多共享点返回 $top 每个答复(如果未设定,100个) 和,当更多的保留,a nextLink.你有三种方法来处理:

// 1. Everything, in one array. Fails as a whole if any page fails.
const all = await connection.getAllListContents<Task>({
  listName: 'Tasks',
  params,
})

// 2. Page by page, as an async iterator. Ends after the last page or the first failure.
for await (const page of connection.iterateListContents<Task>({
  listName: 'Tasks',
})) {
  if (!page.success) throw new Error(page.error)
  process(page.data)
}

// 3. Manually: a single page exposes `nextLink`, which `getNextPage` follows.
const first = await connection.getListContents<Task>({ listName: 'Tasks' })
if (first.success && first.nextLink) {
  const second = await connection.getNextPage<Task>({
    nextLink: first.nextLink,
  })
}

getAllFolderContents 编号 : iterateFolderContents 对文档也这样做 图书馆文件夹。 两者 getAll* 财务报告和审定财务报表 iterate* 接受 maxPages 以上限 走开. getNextPage 只跟踪连接本身主机的链接, 所以您 证书从不发给别处.

重试瞬间失败

设定 retry 关于重试的连接 读取 失败的动作 NETWORK, (中文(简体) ), TIMEOUT,或HTTP 429/502/503/504。 写作从不重试 自动——重试 addListItem 可创建重复.

const connection = createSiteConnection({
  ...options,
  retry: { retries: 3, baseDelayMs: 300, maxDelayMs: 5000 },
})

拖延随着全身的焦躁而成指数增长,如果请求出现,则提前停止 signal 流产。 当SharePoint发送一个 Retry-After 页眉(429/503),即 以等待代替,或者,如果等待时间长于 maxDelayMs,重试停止 失败又随着 retryAfterMs 设置这样你就可以决定。 过 retryOn(failure, attempt) 更改可重试的内容; isTransientFailure 要扩展则导出(默认) .

CAML 查询和 5000 项阈值

$filter 一旦列表通过 SharePoint 的列表, 未索引列失败 视图阈值(默认为5,000项). queryListItems 发送 CAML 查询 改为 GetItems 相反, SQL 服务器对索引列的评价 :

const open = await connection.queryListItems<Task>({
  listName: 'Tasks',
  viewXml: `<View>
    <Query><Where><Eq><FieldRef Name='Status'/><Value Type='Text'>Open</Value></Eq></Where></Query>
    <RowLimit>500</RowLimit>
  </View>`,
  params: new URLSearchParams({ $select: 'Id,Title,Status' }),
})

通过放入页面 <RowLimit> 在风景和逝去 pagingInfo 从 上页的最后一个项目—— Paged=TRUE&p_ID=${last.Id} 当风景 由 ID (默认) 命令. GetItems 是一个 POST, 因此管理请求 文摘被使用;仍作为读取 retry 目标.

请求

batch 在一次往返中发出多个REST电话(SharePoint 2016和 后来;2013年没有 $batch 结束点). 读作个别部分; 连续的写入被组合为一个更改器, 应用SharePoint 解剖论. 每个次级请求都得到自己的回应——失败的请求不会 批量失败, 请检查 ok数字 :

const res = await connection.batch({
  requests: [
    { method: 'GET', path: `_api/web/lists/GetByTitle('Tasks')/items?$top=5` },
    {
      method: 'POST',
      path: `_api/web/lists/GetByTitle('Tasks')/items`,
      body: { __metadata: { type }, Title: 'A' },
    },
    {
      method: 'MERGE',
      path: `_api/web/lists/GetByTitle('Tasks')/items(7)`,
      body: { __metadata: { type }, Title: 'B' },
    },
    { method: 'DELETE', path: `_api/web/lists/GetByTitle('Tasks')/items(8)` },
  ],
})
if (res.success) {
  const [list, created, merged, deleted] = res.data
  if (created.ok) console.log((created.json as { Id: number }).Id)
}

path 相对于该站点( e)_api/...)或同一上的绝对 URL 源代码。 每个子请求的默认值 : Accept: application/json;odata=nometadata, (中文(简体) ), Content-Type: application/json;odata=verbose 当有尸体 If-Match: * 打开 MERGE编号 :PATCH编号 :DELETE; 以 headers。 。 。 . 创建或合并列表项的机构仍然需要 __metadata.type - 那个 批量不为您解析实体类型( s)getListItemType 页:1.

共同选项

每个动作都接受:

  • timeout - 套接字 不活动 超时数以毫秒计。 请求失败 有代码 TIMEOUT 当没有字节到达这么久。 这不是一个帽子 总持续时间; 缓慢但稳定的下载从未超过。 不为所取.
  • signal - 一个 AbortSignal终止生成a Failure 有代码 ABORTED。对于整个呼叫的艰难期限,请使用 signal: AbortSignal.timeout(30_000)。 。 。 .

getDocumentFromLibrary 额外接受 binary (默认) true页:1 返回文件为 Buffer;没有理由关闭它.

TLS 和内部证书

On-premises SharePoint通常在内部CA的证书后. 而不是设定 NODE_TLS_REJECT_UNAUTHORIZED=0 整个进程,通过 CA 连接:

import { readFileSync } from 'node:fs'

const connection = createSiteConnection({
  ...options,
  agentOptions: { ca: readFileSync('/etc/ssl/corp-root-ca.pem') },
})

agentOptions 接受任何东西 https.Agent 是否为 -- ca, (中文(简体) ), cert编号 :key 页:1 客户端证书, rejectUnauthorized, (中文(简体) ), localAddress,习惯 lookup, (中文(简体) ), 等——但 keepAlive 财务报告和审定财务报表 maxSockets,这是NTLM握手 修复。 毒剂按请求创建,后被销毁.

特殊字符

列表标题、文件夹路径和文件名称为%- 编码并有 oData 自动增加一倍,所以 "Bob's Tasks" 财务报告和审定财务报表 'Shared Documents/Q1 2026' 以书面形式工作.

API 密码

完整生成的参考 : b-jones-rfd.github.io/sp-rest-连接。 。 。 .

所有选项类型都导出( E)AddListItemOptions, (中文(简体) ), GetListContentsOptions, (中文(简体) ), ...)下面的每个成员都有记录,所以在你的编辑中徘徊 显示同样的细节。 每个写入动作也接受常见 requestDigest 选项(省略时自动管理); listName 这是 列表的显示标题.

名单

行动所需选项data
getListContents<T>({ listName, params? })—— 说T[] - 一页; nextLink 等更多的东西还剩的时候再设置 * 100个没有 $top。 。 。 .
getAllListContents<T>({ listName, params?, maxPages? })—— 说T[] ——每页收缩.
iterateListContents<T>({ listName, params?, maxPages? })—— 说同步执行器 PageResult<T>。 。 。 .
getNextPage<T>({ nextLink })—— 说T[] ——链接页;仅同源链接.
queryListItems<T>({ listName, viewXml, pagingInfo?, params? })—— 说T[] —— CAML 查询结果通过 GetItems。 。 。 .
getListItem<T>({ listName, spId })—— 说T ——项目对象.
getListItemType({ listName })—— 说string - 比如说. 'SP.Data.InvoicesListItem'。 。 。 .
addListItem<T>({ listName, payload })payload对象T & { Id: number } - 创建的项目.
updateListItem({ listName, spId, patch })patch对象string ——序列补丁 (SharePoint return no body).
deleteListItem({ listName, spId })—— 说''
addAttachmentToListItem({ listName, spId, fileName, payload })payload数字 : Bufferstring ——附件的服务器相对URL.

文件库

行动所需选项data
getFolderContents<T>({ folder, params? })—— 说T[] —— 一页 SP.File 对象(Name, (中文(简体) ), Length(......) ; (......); nextLink 当更多的还剩.
getAllFolderContents<T>({ folder, params?, maxPages? })—— 说T[] ——每页收缩.
iterateFolderContents<T>({ folder, params?, maxPages? })—— 说同步执行器 PageResult<T>。 。 。 .
getDocumentFromLibrary({ folder, fileName })—— 说Buffer ——文件内容.
getDocumentStreamFromLibrary({ folder, fileName })—— 说Readable ——文件内容,未缓存.
checkFolderExistsInLibrary({ folder })—— 说boolean ——缺少文件夹是成功的 false。 。 。 .
createFolderInLibrary({ folder })父关系必须存在string ——新文件夹的服务器相对URL.
addDocumentToLibrary({ folder, fileName, payload, contentLength? })payload数字 : Buffer | Readablestring ——服务器相对URL;覆盖已存在文件.
deleteDocumentFromLibrary({ folder, fileName })—— 说string ——已删除 fileName。 。 。 .

击打

行动所需选项data
batch({ requests })SharePoint 2016+ (英语)BatchResponse[] —— 说 { status, ok, headers, body, json? } 按顺序排列.

认证

行动data
getFormDigestValue({})string 请求摘要,如果你想管理 requestDigest 你自己来.
getAuthToken({})string - NTLM 第3型 Authorization 头曰. 仅诊断;见上文.

错误

SpRestError 财务报告和审定财务报表 parseSharePointError(body) 导出。 前者是 内部运输在行动前给非-2xx反应投出的东西 把它变成一个 Failure;后面的摘录 { code, message } 从任何 OData 出错的身体形状。 NTLM运输本身不属于公众 API (英语). 如果您需要 SharePoint 端点, 请打开此软件包 一个问题.

迁移到 5.0

  • accessToken 不见了. 使用 requestDigest,或者省略它并让 连接管理摘要.
  • addListItem 编号 : updateListItem 只取对象. 替换 payload: JSON.stringify({ __metadata: { type }, ... }) 与 payload: { ... } - 实体类型为你解决.
  • addListItem 解析创建的项目不是JSON的绳子 替换 JSON.parse(res.data).Id 与 res.data.Id。 。 。 .
  • NTLM 帮助者(get, (中文(简体) ), post, (中文(简体) ), auth, (中文(简体) ), request,信息创建者)是 不再出口.

4.x-结构中增加的任何东西 Failure 代码, signal, (中文(简体) ), agentOptions, (中文(简体) ), retry,键入读取,呼出,管理文摘,流出——不变.

捐款

这是一个个人项目 维护我自己使用。 已经出版,所以 但我现在不接受问题 也不接受请求. 安全报告是例外;见 警卫。 。 。 .

如果你想在当地建造:

pnpm install
pnpm dev        # vitest in watch mode
pnpm ci         # lint, test, build, package checks
pnpm docs       # generate the API reference into docs/

版本

交换器见 变化 用于发布注释和打破更改.

许可证

麻省理工学院

版本与发布记录

@b-jones-rfd/sp-rest-connect 共发布 38 个版本,首次发布于 2023/02/25;过去 12 个月发布了 12 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
5.1.1latest2026/10/1128 天前
5.1.02026/10/1128 天前
5.0.02026/10/1128 天前
4.3.02026/10/1128 天前
4.2.02026/10/1128 天前
4.1.02026/10/1128 天前

关于 @b-jones-rfd/sp-rest-connect 的常见问题

@b-jones-rfd/sp-rest-connect 是什么?

使用 SharePoint REST 服务与列表和文档库交互

如何安装 @b-jones-rfd/sp-rest-connect?

在项目目录运行 npm install @b-jones-rfd/sp-rest-connect,或使用 pnpm add / yarn add / bun add。

@b-jones-rfd/sp-rest-connect 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@b-jones-rfd/sp-rest-connect 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@b-jones-rfd/sp-rest-connect 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@b-jones-rfd/sp-rest-connect 可以商用吗?

@b-jones-rfd/sp-rest-connect 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@b-jones-rfd/sp-rest-connect 的下载量有多少?

根据 npm 官方下载统计,@b-jones-rfd/sp-rest-connect 在 2026/10/08 – 2026/11/06 这 30 天内被下载 2,036 次,日均约 68 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@b-jones-rfd/sp-rest-connect 还在维护吗?

最新版本 5.1.1 发布于 2026/10/11(28 天前);至今共发布 38 个版本,其中过去 12 个月发布了 12 个;首次发布于 2023/02/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。