使用Invoke-WebRequest提交multipart表单报Content-Type异常如何解决?
这个问题不只是Content-Type请求头的问题,同时存在多个隐藏错误,具体问题和修复方案如下:
1. 错误设置Content-Length请求头
你在$Headers中手动设置的Content-Length值仅为上传文件本身的大小,并不是整个multipart请求体的总长度,这会直接触发请求校验失败。就算添加了-SkipHeaderValidation参数,服务端收到的请求内容不完整,也会返回错误。
修复方案:直接删除$Headers['Content-Length'] = $Item.Length这一行,Invoke-WebRequest会自动计算并填充正确的Content-Length请求头,无需手动设置。
2. 二进制文件转UTF-8字符串会导致文件损坏
你使用[System.Text.Encoding]::GetEncoding('UTF-8').GetString($fileBytes)将二进制文件内容转码为UTF-8字符串的逻辑是错误的,非文本类型的二进制文件会存在大量不符合UTF-8编码规则的字节,转码过程中会出现乱码、字节丢失,最终上传的文件无法正常打开。
修复方案:直接构造字节数组格式的请求体,不要对二进制文件内容做字符串转码。
3. 字符串拼接请求体存在编码问题
你直接拼接字符串作为请求体,PowerShell中的字符串默认采用UTF-16LE编码,直接传给Invoke-WebRequest时会被自动转码,导致请求体格式错乱。
修复方案:将所有请求内容统一转成UTF-8字节数组后再拼接,作为请求体传入。
4. 边界格式优化
你当前的边界写法本身不会触发Content-Type报错,不过按照multipart/form-data规范可以简化写法:ContentType中的boundary值不需要包含前后的横杠,请求体中的分隔符统一使用--$boundary,结束分隔符使用--$boundary--,避免边界格式歧义。
修复后的参考代码
$GUID = (New-Guid).Guid $boundary = $GUID $ContentType = "multipart/form-data; boundary=`"$boundary`"" $Item = Get-Item -Path $Path $LF = "`r`n" $encoding = [System.Text.Encoding]::UTF8 $bodyParts = New-Object System.Collections.Generic.List[byte[]] # 添加上传文件名字段 $fileNamePart = @" --$boundary Content-Disposition: form-data; name="fileName" $($Item.Name) "@ $bodyParts.Add($encoding.GetBytes($fileNamePart)) # 添加文件内容字段 $fileHeader = @" --$boundary Content-Disposition: form-data; name="file"; filename="$($Item.Name)" Content-Type: application/octet-stream "@ $bodyParts.Add($encoding.GetBytes($fileHeader)) $bodyParts.Add([System.IO.File]::ReadAllBytes($Path)) # 添加share字段 $sharePart = @" --$boundary Content-Disposition: form-data; name="share" $($Share ? 'yes' : 'no') "@ $bodyParts.Add($encoding.GetBytes($sharePart)) # 添加category字段 $categoryPart = @" --$boundary Content-Disposition: form-data; name="category" $CategoryId "@ $bodyParts.Add($encoding.GetBytes($categoryPart)) # 添加结束边界 $endBoundary = @" --$boundary-- "@ $bodyParts.Add($encoding.GetBytes($endBoundary)) # 拼接所有字节为最终请求体 $finalBody = [System.Linq.Enumerable]::SelectMany($bodyParts, [Func[byte[], byte[]]]{$_}).ToArray() Invoke-WebRequest -Uri $Uri -Method Post -Body $finalBody -Headers $Headers -ContentType $ContentType -SkipHeaderValidation
内容的提问来源于stack exchange,提问作者craig

