PowerShell调用Invoke-RestMethod遇GZip头部魔术数错误求助
解决PowerShell调用API的GZip解压错误
我调用某API时,Postman能正常执行,但用PowerShell的Invoke-RestMethod会报错:
Invoke-RestMethod : The magic number in GZip header is not correct. Make sure you are passing in a GZip stream.
已知API返回的响应头:
Connection: close
Content-Encoding: gzip, deflate
Content-Type: application/xml; charset=utf-8
Content-Length: 11778
Date: Fri, 07 Jul 2023 12:49:25 GMT
以下是我编写的PowerShell脚本:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $userAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Authorization", "Bearer $token") $headers.Add("Accept", "*/*") $headers.Add("Accept-Encoding", "gzip, deflate") $headers.Add("Host", "b-fleet03.bellequipment.com:8080") $response3 = Invoke-RestMethod 'https://b-fleet03.bellequipment.com:8080/Fleet' -Method 'POST' -Headers $headers -ContentType "text/plain; charset=utf-8" -UserAgent $userAgent $response3
脚本变体:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $userAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Authorization", "Bearer $token") $headers.Add("Accept", "*/*") ([System.Net.HttpRequestHeader]::AcceptEncoding, "gzip") $headers.Add("Accept-Encoding", "gzip, deflate") $headers.Add("Host", "b-fleet03.bellequipment.com:8080") $response3 = Invoke-RestMethod 'https://b-fleet03.bellequipment.com:8080/Fleet' -Method 'POST' -Headers $headers -ContentType "text/plain; charset=utf-8" -UserAgent $userAgent $response3
Postman成功调用的请求及响应信息:
POST https://b-fleet03.bellequipment.com:8080/Fleet 200 1633 ms Request Headers loco: besa Authorization: Bearer XXXXXXXXX User-Agent: PostmanRuntime/7.32.3 Accept: */* Postman-Token: 29e59bd1-8d66-4140-9d10-90b3447e9694 Host: b-fleet03.bellequipment.com:8080 Accept-Encoding: gzip, deflate, br Connection: keep-alive Content-Length: 0 Response Headers Connection: close Content-Encoding: gzip, deflate Content-Type: application/xml; charset=utf-8 Content-Length: 11779 Date: Mon, 10 Jul 2023 13:55:20 GMT
问题分析
这个错误的核心原因是:API返回了gzip+deflate双重压缩的响应,但Invoke-RestMethod默认的解压逻辑无法正确解析这种嵌套压缩的流。另外你的请求和Postman还有两处关键差异:
- 缺少Postman里的
loco: besa请求头,这可能是API的必填标识 - 你指定了
Content-Type: text/plain但POST没有正文,而Postman是Content-Length: 0的空请求
修复方案
方案一:简化请求头,让PowerShell自动处理编码
移除手动添加的Accept-Encoding,让PowerShell自动协商编码,避免触发API的双重压缩返回;同时补上缺失的loco头,调整空请求的处理:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = [System.Collections.Generic.Dictionary[string,string]]::new() $headers.Add("Authorization", "Bearer $token") $headers.Add("loco", "besa") # 补上Postman里的必填头 $headers.Add("Accept", "*/*") # 明确传递空请求体,匹配Postman的Content-Length:0 $response3 = Invoke-RestMethod 'https://b-fleet03.bellequipment.com:8080/Fleet' ` -Method 'POST' ` -Headers $headers ` -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome ` -Body $null $response3
方案二:手动处理双重压缩(方案一无效时用)
如果API强制返回双重压缩响应,就需要跳过PowerShell的自动解压,手动处理两层压缩流:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # 创建底层请求对象,禁用自动解压 $request = [System.Net.HttpWebRequest]::Create('https://b-fleet03.bellequipment.com:8080/Fleet') $request.Method = 'POST' $request.Headers.Add("Authorization", "Bearer $token") $request.Headers.Add("loco", "besa") $request.Accept = "*/*" $request.UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome $request.AutomaticDecompression = [System.Net.DecompressionMethods]::None # 发送空请求体 $request.ContentLength = 0 $response = $request.GetResponse() # 先解压deflate层,再解压gzip层 $stream = $response.GetResponseStream() $deflateStream = New-Object System.IO.Compression.DeflateStream($stream, [System.IO.Compression.CompressionMode]::Decompress) $gzipStream = New-Object System.IO.Compression.GZipStream($deflateStream, [System.IO.Compression.CompressionMode]::Decompress) # 读取并转换为XML对象 $reader = New-Object System.IO.StreamReader($gzipStream) $responseContent = $reader.ReadToEnd() $xmlContent = [xml]$responseContent $xmlContent # 关闭资源 $reader.Close() $gzipStream.Close() $deflateStream.Close() $response.Close()
内容的提问来源于stack exchange,提问作者user3232808
相关产品推荐
相关产品推荐

