PowerShell 发 POST JSON 这件事,99% 的报错都不是 PowerShell 的锅,而是你把「请求体」和「请求头」搞混了。

我见过太多人写 Invoke-RestMethod 时,把 API Key、数据名、正文全塞进一个字符串里,然后对着 400 错误发呆。这篇就带你用云递数据的两个接口,把「推数据上去」和「把数据取下来」这两件事彻底跑通。全程占位域名 http://你的域名,密钥占位 你的APIKey,你替换成自己的就能直接跑。

PowerShell 发 POST JSON 总报错?先搞清问题出在哪

PowerShell 里发 POST 有两个常用命令:Invoke-WebRequest 和 Invoke-RestMethod。前者返回完整响应对象(含状态码、响应头),后者会自动把 JSON 响应解析成 PowerShell 对象。调试阶段我建议先用 Invoke-RestMethod,因为它对 JSON 更友好,出错时也更容易看出问题。

最常见的三个坑,你对照一下自己中的是哪个:

  • Content-Type 没设对:默认情况下 PowerShell 可能发的是 application/x-www-form-urlencoded,服务端按表单解析,JSON 直接成了乱码字符串。
  • 中文编码没指定:PowerShell 5.1 默认按系统 ANSI 编码发送,UTF-8 中文会变问号或乱码。
  • Body 传了对象却没转 JSON:直接 -Body $obj 传哈希表,某些版本会序列化成 System.Collections.Hashtable 字符串。

记住一条铁律:Body 必须是字符串,且是转好 JSON 的字符串;Content-Type 必须是 application/json;中文场景必须显式指定 UTF-8 字节。下面所有代码都按这条来。

云递数据接口原理:两个 POST 接口搞定存取

云递数据是一个轻量级云端数据存储与分发平台,不需要你买服务器和数据库,任何能发 HTTP 请求的语言或设备都能接入——PowerShell 自然也在列。它的核心就两个接口,一存一取,思路非常干脆:

  • 推送:POST http://你的域名/api/push.php,请求体是 {"api_key":"你的APIKey","dataset":"数据名","data":要存的数据}。其中 api_key 也可以改用请求头 X-Api-Key 传递。
  • 读取:POST http://你的域名/api/pull.php,按写入顺序(FIFO)读取,取走即标记已读,不会重复下发,同时支持分页、按数据名读取。

另外还有一个兼容写法:用 ?api_key=xxx&dataset=yyy 配合纯文本请求体,可以直接存一段文本,适合老程序或简单脚本。但既然是讲 POST JSON,我们主攻 JSON 方式。

这里要特别理解「队列式已读消费」这个设计:它不是普通数据库那种「读多少次都还在」,而是像排队取号——取走了就没了。所以读取接口用错了,数据会被你亲手「读没」。后面第 6 节会专门讲怎么避免。

分步实现:用 PowerShell POST JSON 推送数据

先写一个通用的推送函数。注意 [System.Text.Encoding]::UTF8.GetBytes() 这一步,它是解决中文乱码的关键:把 JSON 字符串转成 UTF-8 字节数组再发出去,而不是让 PowerShell 自己猜编码。

function Push-CloudData {
    param(
        [string]$ApiKey  = "你的APIKey",
        [string]$Dataset = "订单队列",
        [object]$Data
    )

    $url  = "http://你的域名/api/push.php"
    $body = @{
        api_key = $ApiKey
        dataset = $Dataset
        data    = $Data
    } | ConvertTo-Json -Depth 10 -Compress

    $bytes = [System.Text.Encoding]::UTF8.GetBytes($body)

    $resp = Invoke-RestMethod -Uri $url -Method Post `
        -ContentType "application/json; charset=utf-8" `
        -Body $bytes

    return $resp
}

调用它推送一条对象数据,data 字段可以放对象、数组或纯文本,接口会自动规范化:

# 推送一个对象
Push-CloudData -Dataset "订单队列" -Data @{
    orderId = "A20240501"
    user    = "张三"
    amount  = 199.00
    time    = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
}

# 推送一个数组
Push-CloudData -Dataset "设备上报" -Data @(
    @{ dev = "ESP32-01"; temp = 26.5 },
    @{ dev = "ESP32-02"; temp = 27.1 }
)

有一点值得注意:服务端写入时会自动计算哈希去重,内容完全相同的记录只会保留第一条。这是优点也是坑——如果你调试时反复推同一段固定文本,会以为「怎么只存了一条」,其实是去重生效了。测试时记得每次改点内容。

分步实现:用 PowerShell POST JSON 读取数据

读取接口同样是 POST。很多人会疑惑:读取为什么不用 GET?因为参数(api_key、dataset、分页)走 JSON 体更规整,也避免密钥出现在 URL 里被日志记录。读取时我习惯把 api_key 放请求头 X-Api-Key,这样请求体只留业务参数。

function Pull-CloudData {
    param(
        [string]$ApiKey  = "你的APIKey",
        [string]$Dataset = "订单队列",
        [int]$Page       = 1,
        [int]$Size       = 10
    )

    $url = "http://你的域名/api/pull.php"
    $body = @{
        dataset = $Dataset
        page    = $Page
        size    = $Size
    } | ConvertTo-Json -Compress

    $headers = @{ "X-Api-Key" = $ApiKey }
    $bytes   = [System.Text.Encoding]::UTF8.GetBytes($body)

    $resp = Invoke-RestMethod -Uri $url -Method Post `
        -Headers $headers `
        -ContentType "application/json; charset=utf-8" `
        -Body $bytes

    return $resp
}

调用并遍历取回的数据。返回结构里通常包含数据条数和条目列表,我们按通用方式遍历即可:

$result = Pull-CloudData -Dataset "订单队列" -Page 1 -Size 10

Write-Host "本次取回条数:" $result.count

foreach ($item in $result.data) {
    Write-Host "已读:" $item
}

再强调一次:这一步执行完,取回的记录在云端就被标记为已读,下次再拉不会重复下发。所以如果你只是想「看看有什么」,别在生产数据名上随便跑读取脚本。稳妥做法是建一个专门的数据名做测试。

运行效果:控制台查看条数与已读状态

把推送和读取串起来跑一遍,控制台大致是这样的效果:推送几条后,先推的几条在下一次读取时被取走,控制台打印出「本次取回条数」和每一条内容;再执行一次读取,条数变成 0 或只剩没被取走的。这正是队列式消费的直观表现。

除了脚本,你也可以直接登录云递数据控制台,可视化查看每个数据名的条数、容量占用和已读状态,数据还支持下载、编辑、清空、删除。脚本负责自动化,控制台负责肉眼核对,两者搭配最省心。

下面这张表对比一下两个接口的行为,帮你建立直觉:

对比项推送接口 push.php读取接口 pull.php
请求方法POSTPOST
核心作用写入数据到指定数据名按 FIFO 顺序取出数据
是否改变数据状态新增记录(相同内容去重)取走即标记已读
能否重复获取不涉及已读记录不会重复下发
api_key 传递JSON 体或 X-Api-Key 头JSON 体或 X-Api-Key 头
典型场景脚本/设备上报消费端拉取任务

常见坑与注意事项:编码、请求头与限流

编码:中文乱码几乎全是没转字节数组导致的。统一用 [System.Text.Encoding]::UTF8.GetBytes($json),并在 Content-Type 里带上 charset=utf-8。PowerShell 7 默认 UTF-8,但 5.1 一定要手动处理,别偷懒。

请求头:api_key 放 JSON 体或 X-Api-Key 头都支持。我的建议是——推送时放体里方便和 dataset 一起看,读取时放头里避免明文密钥进日志。两者不要同时传冲突的值。

限流:接口有请求频率限制,别写死循环里狂刷。批量上报要加间隔,比如 Start-Sleep -Milliseconds 200,既稳又礼貌。调试时更要克制,否则被限流了你会误以为是代码问题。

去重:内容完全相同的记录只留第一条,测试数据记得每次微调。

会员:新用户注册即赠送 3 天会员免费试用;正式会员月卡 19 元、年卡 99 元,采用卡密充值(YK 开头月卡、NK 开头年卡),多张可叠加、到期顺延。会员到期后数据保留不删除,只是暂停推送和读取,续费即恢复。另外邀请好友注册,好友用卡密开月卡推荐人得 10 天,开年卡得 30 天(天数以后台配置为准),每次续费都奖、自动到账。

常见问题

PowerShell POST JSON 时中文乱码怎么解决?

核心是三步:JSON 字符串用 UTF-8 转成字节数组 [System.Text.Encoding]::UTF8.GetBytes($json) 再作为 Body;Content-Type 写成 application/json; charset=utf-8;PowerShell 5.1 下不要依赖默认编码。三步做齐,中文就不会乱。

api_key 放在 JSON 体里和放在请求头有什么区别?

功能上两者都支持,接口都能识别。区别在于:放体里便于和 dataset、data 一起查看和调试;放 X-Api-Key 请求头里则不会出现在请求体或 URL 中,更不容易被日志记录,读取接口我推荐用请求头方式。注意同一个请求不要同时传两个冲突的值。

读取接口取走数据后还能再读一次吗?

不能。读取接口按写入顺序(FIFO)消费,取走即标记已读,不会重复下发。这正是它适合做任务队列的原因。如果你需要保留原始数据,请在推送端另存一份,或读取后自行落库。

PowerShell 推送的数据支持数组和对象吗?

支持。data 字段可以放对象、数组或纯文本,接口会自动规范化处理。用 ConvertTo-Json -Depth 10 保证嵌套结构完整序列化即可,注意内容完全相同的记录会被去重,只保留第一条。

会员到期后已推送的数据会被删除吗?

不会。会员到期后数据保留不删除,只是暂停推送和读取功能,续费后即恢复使用。所以不用担心到期丢数据,按时续费或提前用卡密叠加即可。

开始使用

本文的代码示例都可以直接在云递数据上运行:注册后即可获得专属 APIKey,在 开发文档 中查看推送、读取接口的完整说明;需要长期使用可以在 会员中心 用卡密开通月卡或年卡;更多实战内容可以浏览技术博客的其他文章。