PowerShell脚本分片上传Dalux API时出现内容大小匹配错误
PowerShell文件分片上传API报错修复方案
问题背景
已有可正常运行的Python分片上传脚本,但转换为PowerShell后,API返回400错误:
{
"httpStatusCode": 400,
"errorCode": "E40004",
"errorCodeMessage": "HeaderValidationFailed",
"message": "Content-Range header size 300000 is not the same as the content size 901216",
"logTime": "2024-02-08T16:02:46.3439873Z"
}
错误原因
原PowerShell脚本中[System.IO.File]::ReadAllBytes($file)[$rangeStart..$rangeEnd]的分片读取方式存在问题:
$rangeStart..$rangeEnd生成包含300000个元素的整数数组,用它索引字节数组时,若文件总字节数小于$rangeEnd,PowerShell会返回从$rangeStart到文件末尾的所有字节,再补充大量$null值,最终数组长度远大于预期,导致实际传输内容与Content-Range声明不符。- 该方式一次性读取整个文件到内存,效率极低且占用过多资源。
修复后的PowerShell脚本
$filePath = "\Downloads\bim\7_LARD_90_99.ifc" $rangeStart = 0 $rangeEnd = 299999 # 自动获取文件总大小,替代硬编码 $totalFileSize = (Get-Item $filePath).Length $headers = @{ "X-API-KEY" = "xxx-xxx-xxx" "Content-Disposition" = "form-data; filename=7_LARD_90_99.ifc" "Content-Type" = "application/octet-stream" "Content-Range" = "bytes $rangeStart-$rangeEnd/$totalFileSize" } try { $bytesToRead = $rangeEnd - $rangeStart + 1 $fileChunkBytes = New-Object byte[] $bytesToRead # 使用文件流精准读取指定范围的字节 using ($fileStream = [System.IO.File]::OpenRead($filePath)) { # 定位到分片起始位置 $fileStream.Seek($rangeStart, [System.IO.SeekOrigin]::Begin) | Out-Null # 读取指定长度的字节 $actualBytesRead = $fileStream.Read($fileChunkBytes, 0, $bytesToRead) # 处理文件末尾的分片(实际读取字节数小于预期) if ($actualBytesRead -lt $bytesToRead) { $fileChunkBytes = $fileChunkBytes[0..($actualBytesRead - 1)] # 更新Content-Range头,匹配实际传输的分片范围 $headers["Content-Range"] = "bytes $rangeStart-$($rangeStart + $actualBytesRead - 1)/$totalFileSize" } } Write-Host "实际读取分片大小: $($fileChunkBytes.Length) 字节" # 用Invoke-WebRequest获取完整响应信息(含状态码) $response = Invoke-WebRequest -Method Post ` -Uri "https://field.dalux.com/service/api/1.0/projects/xxxxxxx/file_areas/yyyyyyy/upload/zzzzzzzzz" ` -Headers $headers ` -ContentType "application/octet-stream" ` -Body $fileChunkBytes ` -UseBasicParsing Write-Host "响应状态码: $($response.StatusCode)" Write-Host "响应内容:" $response.Content | ConvertFrom-Json } catch { Write-Host "发生错误: $_" # 输出API返回的详细错误信息 if ($_.Exception.Response) { $errorStream = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($errorStream) $errorContent = $reader.ReadToEnd() Write-Host "API错误响应: $errorContent" } }
关键修复说明
- 精准读取分片:使用
FileStream的Seek方法定位到分片起始位置,再用Read方法读取指定长度的字节,确保传输内容大小与Content-Range声明完全一致。 - 动态处理末尾分片:若为文件最后一个分片,实际读取字节数可能小于预期,此时自动更新Content-Range头,匹配实际传输的范围。
- 优化内存使用:避免一次性读取整个文件到内存,适配大文件上传场景。
- 完善调试信息:改用
Invoke-WebRequest获取响应状态码和原始内容,便于问题排查。
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

