使用PowerShell向Spring Boot上传ZIP文件的问题(替代Curl)
原Curl上传命令
我们可以通过以下Curl命令将包含压缩LDIF文件的ZIP文件上传至Spring Boot应用,应用接收后会解压并处理LDIF内容:
curl -k -X POST -F "file=@/dev/Cservice.zip;type=application/zip" https://sag01.xxaws.com:10006/Cservice --cert /dev/axis.pem --key /gx/dev/axis.key
需求场景
部分环境无Linux系统,无法使用Curl,需要用PowerShell实现相同的上传功能,同时支持证书认证。
初次尝试的无效脚本
参考相关技术内容修改的PowerShell脚本如下,但运行后Spring Boot虽能收到请求和二进制数据,却无法正常解压处理:
# 参考技术帖子实现 Write-output "RUNNING: 8from-stackoverflow.ps1" $Uri = 'https://sag01.gxaws.com:10006/CService' $fileBytes = [System.IO.File]::ReadAllBytes("G:\Dev\CService.zip"); $enc = [System.Text.Encoding]::GetEncoding('utf-8') $fileEnc = $enc.GetString($fileBytes) Invoke-WebRequest -Uri $Uri -method POST -TimeoutSec 999999 -Certificate (Get-PfxCertificate axisWithKey.pfx) -SkipCertificateCheck ` -Headers @{ "accept"="*/*"} ` -ContentType "multipart/form-data; boundary=WebKitFormBoundaryT2XycANuthCIUwGk" ` -Body ([System.Text.Encoding]::UTF8.GetBytes("--WebKitFormBoundaryT2XycANuthCIUwGk$([char]13)$([char]10)Content-Disposition: form-data; name=`"file`"; filename=`"CService.zip`"$([char]13)$([char]10)Content-Type: application/x-zip-compressed$([char]13)$([char]10)$([char]13)$([char]10))$fileEnc($([char]13)$([char]10)-- WebKitFormBoundaryT2XycANuthCIUwGk--$([char]13)$([char]10)))
服务器日志显示LDIF条目数为0:
2024-03-14 18:12:58,048 DEBUG m.n.g.m.c.u.StringUtils [https-jsse-nio-8888-exec-2] LDIF before reMap method:
2024-03-14 18:12:58,048 DEBUG m.n.g.m.c.u.StringUtils [https-jsse-nio-8888-exec-2] LDIF after reMap method:
2024-03-14 18:12:58,048 DEBUG m.n.g.m.c.s.LDAPService [https-jsse-nio-8888-exec-2] Lidf entries count = 0
对比Curl上传的请求,发现PowerShell上传的Content-Length约为Curl的两倍,问题出在ZIP文件的编码处理上。
最终可用的PowerShell脚本
通过正确构建多部分表单数据解决了问题,脚本如下:
# 参考技术帖子及官方文档实现 $FilePath = 'G:\Dev\CService.zip' $URL = 'https://sag02.xxaws.com:10006/CService' Write-output "ZIP File: $FilePath" Write-output "URL: $URL" $FieldName = 'file' $ContentType = 'application/zip' $FileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open) $FileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new('form-data') $FileHeader.Name = $FieldName $FileHeader.FileName = Split-Path -leaf $FilePath $FileContent = [System.Net.Http.StreamContent]::new($FileStream) $FileContent.Headers.ContentDisposition = $FileHeader $FileContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse($ContentType) $MultipartContent = [System.Net.Http.MultipartFormDataContent]::new() $MultipartContent.Add($FileContent) $Response = Invoke-WebRequest -Body $MultipartContent -Method POST -Uri $URL -TimeoutSec 999999 -Certificate (Get-PfxCertificate geoaxisWithKey.pfx) -SkipCertificateCheck Write-output $Response
请求头差异对比
有效请求与无效请求的关键差异在于Content-Disposition和Content-Type:
有效请求:
Content-Disposition: form-data; name=file; filename=CService.zip^M
Content-Type: application/zip^M无效请求:
Content-Disposition: form-data; name=file; filename=CService.zip; filename*=utf-8''CService.zip^M
Content-Type: application/octet-stream^M
内容的提问来源于stack exchange,提问作者jstack100

