Excel/WPS网络函数库:让公式直连HTTP接口的封装实践

发布时间:2026/10/8 2:58:24
Excel/WPS网络函数库:让公式直连HTTP接口的封装实践 简介Excel/WPS用户常苦于无法在表格中直接抓取网页数据或调用网络接口。这份资源将常用网络函数库封装为便于导入的工具包面向有一定VBA基础的办公自动化人员解决在电子表格中发送HTTP请求、解析返回数据、实现快递查询等实时数据获取问题。压缩包共67个文件、55.44MB核心是31个DLL动态链接库如RestSharp、Spire.XLS、Newtonsoft.Json另有10个XML配置/说明、7个JS脚本、3个XLSX示例文档及一个EXE更新工具还附带Chrome插件文件方便在浏览器与Excel间联动取数。目前已有2572人学习下载可作为在Excel/WPS中集成网络功能的现成参考。包内含ExcelAPIUpdateTool工具可一键更新函数库配套“公式大全V1.0”“翻译工具”“快递查询”等实例帮助用户理解VBAMSXML/HTTP的调用流程并快速改造到自己的表格中。1. 网络函数库是什么Excel 与 WPS 里公式直连网络的黑匣子早会上运营同事又在手工查物流把单号复制到网页、看时效、再粘回表格四十行单号折腾了半小时。那段时间我刚好在整理一套“网络函数库-excel、wps用”的自定义函数让表格里的单元格直接写NetGet(https://…)拿回 JSON再用一行NetJson(…, data.deliveryTime)把时效字段提出来。所谓网络函数库就是把这套 HTTP 请求、JSON 解析、超时重试、请求头拼装封装成一组工作表函数让不写代码的人也能像用SUMIF一样消费网页接口。它解决的是表格里的联网取数需求行情、汇率、天气、内部系统 API、政务公开数据以及 Excel 和 WPS 两头通吃的问题。适合不想开 Python、又需要在表格里频繁拉接口数据的表哥表姐。这个方向不新鲜但现成方案大多是“点按钮取数”的插件不是公式级的联动方案所以我决定自己封装一套。2. 先跑通最小函数为什么自己封装 GET 而不是依赖内置功能2.1 内置的 WEBSERVICE 和 Power Query 卡在哪Excel 自己带了一个WEBSERVICE函数很多人的第一反应是拿它顶一阵子。但它的问题很具体不能自定义请求头超时控制基本没有返回慢而且不是所有版本都能用。另一个看似强大的方案是 Power Query从 Web 拉数据、清洗、加载功能完整可每次刷新要么手动点要么配计划数据进了表之后想做到“某个单元格参数变了就自动重查”它做不到。WPS 表格的情况类似公式层面没有现成的网络接口函数多数人最后都会落回复制粘贴。所以更常见的做法是把请求逻辑写成一组成员自定的函数放进加载项或宏模块里让业务同事在单元格里直接组装参数。这其实就是“网络函数库”这个标题的落点不是再造一个爬虫工具而是把表格变成接口的客户端。函数级的好处是联动比如城市名加上后缀、日期变了F9 重算就能拿到新结果不需要开别的工具。2.2 VBA 还是 WPS JS 宏选型看环境如果团队都在 Windows 上用 ExcelVBA 是默认选择资料多、老文件多、同事里的“半懂哥”也能帮你查错。WPS 表格这边装了 VBA 兼容插件之后同一份 VBA 代码基本能跑WPS 新版也自带 JS 宏也就是基于 JavaScript 的宏环境不需要额外装插件。我的选型习惯是优先保证 Excel 上能用 VBA同时保持一份 WPS JS 宏实现函数接口保持一致。这样同一个工作簿换到没装 VBA 插件的 WPS 上就改用 JS 宏版本而不是让同事干瞪眼。JS 宏有个 VBA 比不上的地方JSON.parse、encodeURIComponent这些能力是 JavaScript 引擎原生就有的。VBA 里要解析 JSON 还得另想办法。反过来VBA 的On Error和Err.Description在 JS 宏里没有对应物只能用try/catch。两套代码不能一字不差地复制但函数签名可以保持一致。2.3 最小跑通的 GET 请求函数VBA 版我一般先做一个最小函数能返回纯文本再逐步扩展。下面这段就是网络函数库的地基Public Function NetGet(ByVal url As String, Optional ByVal timeout As Long 5000) As String On Error GoTo Fail Dim http As Object Set http CreateObject(MSXML2.XMLHTTP) http.Open GET, url, False http.setTimeouts timeout, timeout, timeout, timeout http.Send If http.Status 200 Then NetGet http.responseText Else NetGet HTTP_ERROR: http.Status End If Exit Function Fail: NetGet NET_ERROR: Err.Description End Function这里有几个参数和写法不能改错。CreateObject(MSXML2.XMLHTTP)是为了不依赖引用换一台没勾选 Microsoft XML 库的电脑也能跑。Open的第三个参数必须是False也就是同步请求这是自定义函数能不能在单元格里用回来的关键异步请求在公式环境里会直接返回空很多新手在这个地方翻车。setTimeouts的前三个参数分别管连接、发送、接收第四个是超时总时限我一般统一传同一个值。返回约定上非 200 状态返回HTTP_ERROR:xxx异常返回NET_ERROR:xxx这样外层可以靠前缀做重试判断公式里也能用IF拦截错误。2.4 WPS 里怎么跑同一套函数如果你的 WPS 装了 VBA 兼容插件上一节的 VBA 代码可以原样放进模块里。没装插件的话就用 WPS 的 JS 宏编辑器新建模块写一个功能等价的版本function NetGet(url, timeout) { timeout timeout || 5000; var xhr new XMLHttpRequest(); try { xhr.open(GET, url, false); xhr.timeout timeout; xhr.send(); if (xhr.status 200) { return xhr.responseText; } return HTTP_ERROR: xhr.status; } catch (e) { return NET_ERROR: e.message; } }JS 宏里没有On Error所有异常都在try/catch里兜住。XMLHttpRequest是 WPS 内置对象不用额外引用。这里有个 WPS 特有的麻烦不同版本对 JS 宏自定义函数进公式的支持不一样有的版本单元格输入NetGet(...)会提示名称错误但同一段代码在宏编辑器里又能正常执行。遇到这种情况先运行一次宏、确认宏功能正常再回头看公式个别版本重新打开文件也能解决问题。这不是代码问题是 WPS 对 JS 宏函数注册机制不一致造成的“玄学”现象。3. 从 GET 到 JSON把函数库扩成一套可直接写进单元格的接口3.1 函数签名与返回约定函数库一旦要给同事用接口就要稳定。我常用的网络函数库包含六个函数签名如下表函数名作用必填参数可选参数NetGetGET 请求返回响应文本urltimeout、headersNetPostPOST 请求返回响应文本url、bodycontentType、timeout、headersNetJson从 JSON 里按路径取字段json、path无NetUrlEncodeURL 编码textplusNetGetRetry带重试的 GETurltimeout、retriesNetCached带缓存的 GETurlttl、timeout错误返回统一用前缀区分HTTP_ERROR:表示请求发出去了但状态码不对NET_ERROR:表示网络层异常JSON_ERROR:表示解析失败。这个约定能帮公式层做判断比如IF(ISNUMBER(SEARCH(HTTP_ERROR, B2)), 接口挂了, B2)。3.2 实现 NetPost 和自定义请求头很多接口要 POST 表单或 JSON还要带 token所以 NetPost 得支持请求头。VBA 的setRequestHeader只能一次设一个而工作表公式里没法传数组常见的做法是把多个头拼成一个字符串用|分隔函数内部再拆开Public Function NetPost(ByVal url As String, ByVal body As String, _ Optional ByVal contentType As String application/json, _ Optional ByVal headers As String , _ Optional ByVal timeout As Long 5000) As String On Error GoTo Fail Dim http As Object Set http CreateObject(MSXML2.XMLHTTP) http.Open POST, url, False http.setTimeouts timeout, timeout, timeout, timeout http.setRequestHeader Content-Type, contentType Dim h As Variant If Len(headers) 0 Then For Each h In Split(headers, |) Dim kv As Variant kv Split(h, :) If UBound(kv) 1 Then http.setRequestHeader Trim$(kv(0)), Trim$(kv(1)) Next End If http.Send body If http.Status 200 Then NetPost http.responseText Else NetPost HTTP_ERROR: http.Status End If Exit Function Fail: NetPost NET_ERROR: Err.Description End Function参数设计上contentType默认给application/json因为现在内部接口大多是 JSON 交互遇到表单提交公式里再显式传application/x-www-form-urlencoded。headers字符串的格式是Authorization:Bearer xxxx|X-Tenant:1002用竖线分隔多个头函数内部拆完后还要Trim掉首尾空格否则服务端可能因为一个空格拒绝认证。3.3 JSON 解析VBA 的三种路径和 WPS 的一步到位VBA 解析 JSON 有三条路一是ScriptControl需要 32 位环境二是正则提取三是引入第三方 JSON 解析库。ScriptControl在 64 位 Excel 上会直接崩这个坑后面单讲。第三方 JSON 库功能完整但要维护一个额外模块。我自己的习惯是能用 JS 宏的地方用JSON.parse必须在 Excel VBA 里解析时先用正则做简单取值应付八成场景。正则版NetJson只做单层字符串和数字字段的提取Public Function NetJson(ByVal json As String, ByVal field As String) As String Dim re As Object Set re CreateObject(VBScript.RegExp) re.Pattern \ field \\s*:\s*([^]*|[\d.]|true|false|null) If re.Test(json) Then Dim raw As String raw re.Execute(json)(0).SubMatches(0) If Left$(raw, 1) Then NetJson Mid$(raw, 2, Len(raw) - 2) Else NetJson raw End If Else NetJson JSON_ERROR:field End If End Function这个正则匹配字段名: 值能取字符串、数字、布尔值遇到嵌套对象和数组就无能为力。深层字段用 WPS JS 宏的NetJson版本更省事它支持点路径和数组下标function NetJson(json, pathExpr) { try { var obj JSON.parse(json); var keys pathExpr.replace(/\[(\d)\]/g, .$1).split(.); var value obj; for (var i 0; i keys.length; i) { value value[keys[i]]; if (value undefined || value null) { return JSON_ERROR:path; } } if (typeof value object) { return JSON.stringify(value); } return String(value); } catch (e) { return JSON_ERROR: e.message; } }路径写法上data.list[0].name会被正则先替换成data.list.0.name再按点号拆分逐级取。这个方案比eval安全得多不会因为接口返回值里夹带恶意字段而执行脚本。3.4 批量刷新循环请求与写回单元格单条公式发一个请求没问题但一个表格里塞五百条NetGet公式接口和 Excel 都会卡。我一般把实时性要求高的接口拉到一个专门的刷新区域用按钮触发一次批量请求把结果回填到单元格。这样既保留公式联动又避免几百个请求一起打过去。Sub RefreshUrls() Dim rng As Range, c As Range Set rng Range(A2:A Cells(Rows.Count, 1).End(xlUp).Row) Dim results() As String ReDim results(1 To rng.Count, 1 To 1) Dim i As Long, resp As String i 1 For Each c In rng If Len(c.Value) 0 Then resp NetGet(CStr(c.Value), 5000) If Left$(resp, 4) HTTP Or Left$(resp, 4) NET_ Then results(i, 1) ERROR Else results(i, 1) resp End If End If i i 1 DoEvents Next Range(B2).Resize(rng.Count, 1).Value results End Sub代码逻辑很直白先把 A 列每个单元格当成 URL逐个请求把响应装进二维数组最后一口气写入 B 列。这里有两个细节值得注意一是结果数组和 Range 的行列起点要对齐Resize(rng.Count, 1)表示从 B2 开始向下扩展同样行数二是DoEvents在长循环里把控制权还给界面避免表格长时间显示“未响应”。逐格写入和数组整体写入的性能差距在几百行时就能明显感觉到。4. 参数设计与场景调优URL 编码、超时、请求头与缓存刷新4.1 URL 编码中文参数为什么一请求就乱码直接拼 URL 带中文十次有八次要么报 4xx要么服务端查到的是乱码。原因不是接口不支持中文而是 URL 里的非 ASCII 字符必须按百分号编码。VBA 里没有原生的encodeURIComponent但 Excel 2013 之后的版本提供了WorksheetFunction.EncodeURL可以直接用Public Function NetUrlEncode(ByVal text As String) As String NetUrlEncode Application.WorksheetFunction.EncodeURL(text) End FunctionWPS 的 JS 宏版本就用 JavaScript 原生能力一行搞定function NetUrlEncode(text) { return encodeURIComponent(text); }这里有一个容易被忽略的参数差异编码后空格会变成%20还是。大部分现代服务端两种都认老一些的系统只认%20。EncodeURL在不同版本里行为不完全一致如果遇到服务端把当成空格、但你要传的就是字面加号就得在编码后把替换成%2B。我一般会在函数里加一个可选参数plus默认False需要时再开。4.2 超时与重试把网络抖动挡在公式外面接口偶发超时是常态函数库必须内置重试。重试不是简单地把同一请求多发几遍要设定重试上限和间隔避免把接口拖垮。下面这个NetGetRetry直接复用前面的NetGetPublic Function NetGetRetry(ByVal url As String, _ Optional ByVal timeout As Long 3000, _ Optional ByVal retries As Long 2) As String Dim resp As String Dim i As Long For i 0 To retries resp NetGet(url, timeout) If Left$(resp, 4) HTTP And Left$(resp, 4) NET_ Then NetGetRetry resp Exit Function End If Next NetGetRetry resp End Function判断是否重试看返回串前缀只要不是HTTP_ERROR或NET_ERROR开头就认为是有效响应立即退出循环。重试次数默认 2也就是最多打三遍。超时时间我给 3 秒内部接口一般够了外部公共服务接口网络波动大可以调到 5 秒。重试之间要不要加间隔常见做法是直接连续重试因为表格取数场景里等待本身是廉价的频繁重试才真的会惹恼接口提供方。4.3 带 Token 的请求头怎么设计业务接口基本都要鉴权token 要么放在请求头里要么放在 URL 参数里。请求头更干净。把 token 直接写死在函数代码里是最差的做法换 key 要改宏、改完还要重新分发文件。我习惯的做法是把请求头字符串放在工作表的隐藏单元格里公式引用那个单元格。Public Function NetGetWithHeaders(ByVal url As String, ByVal headers As String, _ Optional ByVal timeout As Long 5000) As String On Error GoTo Fail Dim http As Object Set http CreateObject(MSXML2.XMLHTTP) http.Open GET, url, False http.setTimeouts timeout, timeout, timeout, timeout Dim h As Variant, kv As Variant If Len(headers) 0 Then For Each h In Split(headers, |) kv Split(h, :, 2) If UBound(kv) 1 Then http.setRequestHeader Trim$(kv(0)), Trim$(kv(1)) Next End If http.Send If http.Status 200 Then NetGetWithHeaders http.responseText Else NetGetWithHeaders HTTP_ERROR: http.Status End If Exit Function Fail: NetGetWithHeaders NET_ERROR: Err.Description End FunctionSplit(h, :, 2)的第二个参数写成 2意思是只拆成两段这样 token 本身带冒号也不会被误拆。表头配置示例Authorization:Bearer eyJxxx|X-Tenant:1002。放在单元格里的好处是同事调接口时不用打开 VBA 编辑器直接改单元格就能换 token。宏代码只负责“怎么传”不负责“传什么”。4.4 缓存与手动刷新别让每次重算都打接口公式一多每次 F9 重算都会把接口请求重新打一遍。Excel 的公式重算频率比你想的高比如筛选、排序、输入数据都可能触发重算。这时候要加一层进程内缓存。VBA 里用Static变量保存一个Scripting.Dictionary按 URL 缓存响应文本和时间戳Public Function NetCached(ByVal url As String, Optional ByVal ttl As Long 300) As String Static cache As Object Static stamp As Object If cache Is Nothing Then Set cache CreateObject(Scripting.Dictionary) Set stamp CreateObject(Scripting.Dictionary) End If If cache.Exists(url) And Timer - stamp(url) ttl Then NetCached cache(url) Exit Function End If Dim resp As String resp NetGet(url, 5000) If Left$(resp, 4) HTTP And Left$(resp, 4) NET_ Then cache(url) resp stamp(url) Timer End If NetCached resp End Functionttl默认 300 秒也就是五分钟内同一个 URL 只会真正请求一次之后的公式重算都直接返回缓存。想立即拿新数据就按CtrlAltF9强制重算整个工作簿或者重启 Excel 清掉进程内缓存。注意这个缓存只活在当前 Excel 进程里关文件再打开就没了下一次首个请求会重新打接口这是正常现象不是 bug。5. 常见问题排查宏被禁用、编码乱码与 JSON 解析的踩坑清单5.1 Excel 加载项被禁用导致公式变 #NAME?现象同事从共享盘拷走 xlam 加载项打开后所有NetGet公式都显示#NAME?加载项列表里也找不到它。原因Office 出于安全策略把从网络或 U 盘拷来的加载项默认禁用了加载项根本没有加载Excel 不认识NetGet这个函数。解决右键文件 → 属性 → 解除锁定再把 xlam 复制到本机加载项目录比如%AppData%\Microsoft\AddIns最后在 Excel 的“文件 → 选项 → 加载项 → 转到”里勾选。WPS 里对应的是菜单里的“工具 → 加载项”勾选后重启 WPS 再验证。这个现象在“Excel 加载项被禁用”的搜索里非常高频本质都是信任中心拦住了代码。5.2 WPS 里 VBA 能跑、单元格却不识别自定义函数现象在 WPS 的 VBA 兼容环境里写完NetGet宏对话框能执行但单元格输入NetGet(...)报名称错误。原因WPS 对自定义函数的注册机制和 Excel 不一样某些版本需要先运行一次宏函数名才会被公式引擎识别。解决先随便在单元格写NetGet(https://example.com)然后按 F5 打开宏对话框手动执行一次NetGet如果执行成功公式一般就认了。还不行就检查文件后缀必须是.xlsm.xlsx里宏代码会被直接丢弃。同样的现象在 WPS 的 JS 宏里也常见我的办法是写完后关掉工作簿重新打开一次再敲公式。5.3 中文参数返回乱码或不返回现象NetGet拼接了中文城市名返回的 JSON 里出现或者接口直接查不到。原因有两个一是没做 URL 编码二是响应的编码不是 UTF-8responseText在解码时用了错误的字符集。解决参数一律先过NetUrlEncode如果 URL 编码做了还乱码就改用responseBody加ADODB.Stream解码With CreateObject(ADODB.Stream) .Type 1 .Open .Write http.responseBody .Position 0 .Type 2 .Charset UTF-8 NetGet .ReadText End With这段替代http.responseText能解决大部分乱码。如果服务端返回 GBK把Charset改成GBK再试。血泪经验是先确认接口自己返回的是什么编码再去动函数别一上来就在编码上瞎试。5.4 64 位 Excel 里 ScriptControl 直接崩现象调用CreateObject(ScriptControl)时64 位 Excel 报“ActiveX 组件不能创建对象”严重的直接把进程带崩。原因ScriptControl是 32 位 COM 组件在 64 位 Office 里基本不可用。解决网络函数库里不要绑定ScriptControl改用正则方案或第三方 JSON 解析库如果目标机器是 64 位 Excel优先把 JSON 解析放到 WPS JS 宏里用JSON.parse。这个坑隐蔽在代码在 32 位机器上一切正常换到 64 位就翻车而且崩的是 Excel 不是公式。5.5 HTTPS 证书校验失败的内部测试环境现象请求内部测试环境接口NetGet返回NET_ERROR:-2147012744这个错误码指向证书校验失败。原因很多测试环境用的是自签名证书系统证书库不信任。解决先请网络同事把测试环境证书链补齐如果实在来不及可以在代码里改用一个可关闭证书校验的组件Set http CreateObject(MSXML2.ServerXMLHTTP.6.0) http.SetOption 2, True SXH_OPTION_IGNORE_SERVER_CERTIFICATE_ERRORS注意这行代码只是临时绕过证书校验绝对不能在生产环境里做否则中间人攻击一点防护都没有。能配证书就配证书绕过校验只是后悔药不是常规治疗。6. 把网络函数库打包成加载项分发、调试与验证的一劳永逸函数代码稳定之后别把宏直接塞进业务工作簿那样每个文件都带一份代码后续改 bug 要挨个通知。我一般把函数库单独存成一个.xlam加载项VBA 编辑器里对工程点右键选择“导出文件”按模块导出备份然后“文件 → 另存为 → Excel 加载项 (.xlam)”。分发时提醒同事先解除文件锁定再放进加载项目录。WPS 用户则把 JS 宏代码复制到自己的 JS 宏工程里因为 WPS 对 xlam 的加载支持不稳定直接用 JS 宏更省事。调试这类自定义函数有个顺序问题不要一上来就在单元格里试。先用CtrlG打开立即窗口执行?NetGet(https://example.com)看原始返回再用Debug.Print输出错误信息。验证接口本身用一个最简单的命令行请求curl -s -o /tmp/resp.txt -w %{http_code} https://api.example.com/data先确认接口返回 200再看resp.txt内容最后才回到 Excel 里查函数。我第一版函数库没加缓存领导开表后五百行公式同时打内部接口把测试服务打挂了。后来所有实时性要求不高的接口全走NetCached再加一个手动刷新按钮才把问题止住。这个“缓存优先、实时手动”的习惯我保留到了后面所有表格型的接口消费场景里。做网络函数库这件事最值钱的不是代码本身是那套“怎么设计参数、怎么约定错误、怎么防重算风暴”的边界感。希望这些踩坑经验帮到你。本文还有配套的精品资源点击获取