PowerShell使用Invoke-RestMethod上传二进制文件数据损坏如何解决?
解决方案
你遇到的二进制数据损坏问题,根源是将原始文件字节转为字符串后再传输:Invoke-RestMethod处理字符串类型的请求体时,会默认将字符串转码为ISO-8859-1编码,超出该编码范围的字节就会被替换为近似字符,导致文件损坏。
正确的做法是全程使用字节数组构造multipart/form-data请求体,完全跳过字符串转码步骤,即可保证二进制数据不被修改。
完整实现代码
$filePath = 'C:\favicon.ico' $boundary = [System.Guid]::NewGuid().ToString() $CRLF = "`r`n" # 读取文件原始字节,不做任何编码转换 $fileBytes = Get-Content $filePath -Encoding Byte -Raw # 构造各部分的字节内容 $bodyParts = @() # 1. 文件字段部分 $bodyParts += [System.Text.Encoding]::UTF8.GetBytes("--$boundary$CRLF") $bodyParts += [System.Text.Encoding]::UTF8.GetBytes('Content-Disposition: form-data; name="upload_file"; filename="favicon.ico"'+$CRLF) $bodyParts += [System.Text.Encoding]::UTF8.GetBytes("Content-Type: application/octet-stream$CRLF$CRLF") $bodyParts += $fileBytes $bodyParts += [System.Text.Encoding]::UTF8.GetBytes($CRLF) # 2. 普通字段foo $bodyParts += [System.Text.Encoding]::UTF8.GetBytes("--$boundary$CRLF") $bodyParts += [System.Text.Encoding]::UTF8.GetBytes('Content-Disposition: form-data; name="foo"'+$CRLF+$CRLF) $bodyParts += [System.Text.Encoding]::UTF8.GetBytes("bar$CRLF") # 3. 普通字段baz $bodyParts += [System.Text.Encoding]::UTF8.GetBytes("--$boundary$CRLF") $bodyParts += [System.Text.Encoding]::UTF8.GetBytes('Content-Disposition: form-data; name="baz"'+$CRLF+$CRLF) $bodyParts += [System.Text.Encoding]::UTF8.GetBytes("qux$CRLF") # 4. 结束边界 $bodyParts += [System.Text.Encoding]::UTF8.GetBytes("--$boundary--$CRLF") # 合并所有字节为完整请求体 $fullBody = [System.Linq.Enumerable]::Concat([byte[][]]$bodyParts) # 发送请求,直接传入字节数组类型的Body,不会触发转码 Invoke-RestMethod -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $fullBody -Method Post -Uri 'http://localhost/upload.php'
说明
- 所有非二进制内容统一用UTF-8编码转字节,兼容绝大多数服务端解析规则
- 文件字节直接加入请求体,全程不经过字符串转换,不会出现0x80-0x9F区间字符被替换的问题
- 不需要使用
-InFile参数,即可同时传输二进制文件和任意数量的普通表单字段
如果需要兼容其他编码的字段值,只需要修改对应字段部分的编码方式即可,不会影响文件二进制数据。
内容的提问来源于stack exchange,提问作者CJ Dennis
相关产品推荐
相关产品推荐

