如何通过网络请求传递数组
How to pass an array via web-request
情况:
我们从某些网络服务(PowerShell 脚本 运行 每晚自动收集许多报告,并且每天都在手动模式下(在网络表单上拖放) ) 此报告已加载到我们的数据库中。
现在我们的 IT 部门给了我们一个 API 可以在没有用户交互的情况下处理这项工作。
问题:
如求职信中所写(关于此 API),它等待 reports[n]
数组和文件。可以用 PHP 和 curl:
来完成
$report = 'report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip';
$cfile = new CURLFile(realpath($report),'application/zip',$report);
$PostData = array("reports[0]"=>$cfile);
但是如何通过 PowerShell 发送名为 reports[n]
的数组?
我试过的:
$url = "https://test.example.com/uploadAPI/upload.php"
$Source = "D:\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
$contentType = "multipart/form-data"
$Username = "ApiUploadKey"
$Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))}
$FileContens = get-content $Source
$PostData = @{"reports[0]" = $FileContens;}
#$reports = @($FileContens,'application/zip',$Source)
(Invoke-WebRequest -uri $url -Method POST -Headers $Headers -Body $PostData -ContentType $contentType).Content
#Invoke-RestMethod -uri $url -Method POST -Headers $Headers -Body $PostData -ContentType $contentType
这给了我一个我正在通过 not-a-report.
的回复
编辑 2016-10-11
进一步调查让我想到这个 answer and this article。我尝试使用 boundary
:
clear
$url = "https://test.example.com/uploadAPI/upload.php"
$filename = "report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
$Source = "D:\"+$filename
$Username = "ApiUploadKey"
$Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))}
$FileContens = get-content $Source
$enc = [System.Text.Encoding]::GetEncoding("iso-8859-1")
$fileBin = [IO.File]::ReadAllBytes($Source)
$fileEnc = $enc.GetString($fileBin)
$boundary = [System.Guid]::NewGuid().ToString()
$LF = "`n"
$contentType = "multipart/form-data; boundary=--$boundary"
#$bodyLines = "--"+$boundary+$LF+"Content-Disposition: form-data; name=`"reports[]`"; filename=`""+$filename+"`""+$LF+$LF+"Content-Type: application/zip"+$LF+"--"+$boundary+"--"+$LF+$LF+$FileContens+$LF+"--"+$boundary
$bodyLines = (
"--$boundary", #I have tried reports[0] here too
"Content-Disposition: form-data; name=`"reports[]`"; filename=`"$filename`"", # filename= is optional
"Content-Type: application/zip",
"",
#$FileContens,
$fileEnc,
"--$boundary--"
) -join $LF
try {
#Invoke-WebRequest -Uri "https://asrp.cntd.ru/uploadAPI/" -Headers $Headers -WebSession $ws
Invoke-RestMethod -Uri $url -Body $bodyLines -Method POST -Headers $Headers -ContentType $contentType -TimeoutSec 50
}
catch [System.Net.WebException] {
Write-Error( "FAILED to reach '$url': $_" )
throw $_
}
但结果相同。
我也试过这个:
$wc = new-object System.Net.WebClient
$wc.Credentials = new-object System.Net.NetworkCredential("ApiUploadKey","")
ls "D:\*.zip" | foreach {
$wc.UploadFile('https://test.example.com/uploadAPI/upload.php', $_.FullName )
write-host $_.FullName
}
还有一个来自这个 answer 的解决方案:
Invoke-RestMethod -Uri $url -InFile $Source -ContentType "multipart/form-data" -Method POST -Headers $Headers
总是相同的响应 - 不是报告
编辑 2016-10-17
curl
我已经为 windows 下载了 curl
。并像这样使用它:
curl.exe https://test.example.com/uploadAPI/upload.php --user ApiUploadKey: --form "reports[0]=@d:\report_746_226255_20161010_1635.zip;type=application/zip"
这给了我:
[{"code" : 102 , "guid" : "{23CE9F7F-BEC8-4D4C-8AC3-2865CFA94FBD}" , "id" : "5804902bc73a2475177464", "filename" : "report_746_226255_20161010_1635.zip"}]
所以使用 curl 效果很好!
提琴手
不知道 post 的确切日志。
当我这样发送文件时:
POST https://test.example.com/uploadAPI/upload.php
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Host: test.example.com
Authorization: Basic ...
Content-Length: 21075175
请求正文:
---------------------------acebdf13572468
Content-Disposition: form-data; name="reports[]"; filename="report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip"
Content-Type: application/zip
<@INCLUDE *D:\report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip*@>
---------------------------acebdf13572468--
我得到了
HTTP/1.1 200 OK
Date: Mon, 17 Oct 2016 10:04:43 GMT
Server: Apache/2.4.20 (Win64) OpenSSL/1.0.2h PHP/7.0.6
X-Powered-By: PHP/7.0.6
Set-Cookie: SESSION_UPLOAD_ID=.....; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Connection: close
Content-Length: 193
Content-Encoding: none
Accept-Ranges: bytes
Content-Type: text/html; charset=UTF-8
[{"code" : 102 , "guid" : "{B67A9D89-368B-4665-96AC-77C2CA0F4766}" , "id" : "5804a23be4152532018928", "filename" : "report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip"}]
PHP 代码使用 Curl class 并将 $PostData 设置为:
$PostData = array("reports[0]"=>$cfile);
$PostData 是一个 key/value 对数组(在 PHP 中),键名为 Reports[0]。它只是一个字符串名称,表示键而不是数组元素。
在 curl 命令行工具中,我们可以使用以下命令上传文件:
curl.exe -F Reports[0]=@"I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://MyServer/uploader/api/upload
或者,它可能是(注意关键 Reports[0][2][3] ):
curl.exe -F Reports[0][2][3]=@"I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://asd-pc/uploader/api/upload
-F 为输入形式key/value对
注意文件名前的@
在你的服务器上试一下,在Fiddler中查看session就知道curl和PHP是如何向服务器发送请求的。
对于具有其他键名的其他文件,例如 Reports1.
,您可以传递其他参数,例如 -H (header) -v(详细)-F
我用我的网络服务器 运行 将文件上传到服务器的 Web Api2 服务测试了这段代码,运行 没问题。
所以,问题是:如何将该代码转换为与 Powershell 一起工作。
在 curl PHP 或命令行工具中,它会自动准备 Header 和请求 Body 以支持 Multipart/form-data.
的文件上传
两个 Powershell 命令:Invoke-WebRequest 和 Invoke-RestMethod 都不知道如何格式化请求 body 以符合 Multipart/form-data 中给出的标准RFC Forms: multipart/form-data
您必须手动设置消息 body 然后调用您的调用
以下脚本使用 powershell 将文件上传到网络服务器。
我设置 Content-Type: application/octet-stream 以支持任何类型,包括 zip 文件。
function Upload-File ( $InFile,$Uri )
{
$Username = "ApiUploadKey"
$Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))}
$LF = "`n"
$fileName = Split-Path $InFile -leaf
$boundary = [System.Datetime]::Now.Ticks.ToString()
$binaryData = [System.IO.File]::ReadAllBytes($InFile)
$binaryEncoded=[System.Text.Encoding]::GetEncoding("iso-8859-1").GetString($binaryData)
$ContentType = "application/octet-stream"
$body = @"
--$boundary
Content-Disposition: form-data; name=`"Reports[0]`"; filename=`"$fileName`"
Content-Type: $ContentType
$LF
$binaryEncoded
--$boundary--
$LF
"@
try
{
return Invoke-RestMethod -Uri $Uri -Method Post -ContentType "multipart/form-data; boundary=$boundary" -Body $body -Headers $Headers
}
catch [Exception]
{
$PSCmdlet.ThrowTerminatingError($_)
}
}
#-- test the function ---------------------------------
cls
$uri = "http://MyServer/uploader/api/upload"
$filePath = "I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
$response = Upload-File -InFile $filePath -Uri $uri #-Credential $credentials
$response
fiddler
的输出session
POST http://MyServer/uploader/api/upload HTTP/1.1
Authorization: Basic QXBpVXBsb2FkS2V5Og==
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 6.1; en-US) WindowsPowerShell/5.0.10586.117
Content-Type: multipart/form-data; boundary=636123339963709320
Host: MyServer
Content-Length: 379
Connection: Keep-Alive
--636123339963709320
Content-Disposition: form-data; name="Reports[0]"; filename="report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
Content-Type: application/octet-stream
xxxxxxxxxxxxxxxxxxxxxxxxxxxStream of byte sxxxxxxxxxxxxxxx
在上面的 session 数据中,您会看到 Reports[0] 的标题为 name
您可以在命令中使用相同的代码:Invoke-WebRequest
情况:
我们从某些网络服务(PowerShell 脚本 运行 每晚自动收集许多报告,并且每天都在手动模式下(在网络表单上拖放) ) 此报告已加载到我们的数据库中。
现在我们的 IT 部门给了我们一个 API 可以在没有用户交互的情况下处理这项工作。
问题:
如求职信中所写(关于此 API),它等待 reports[n]
数组和文件。可以用 PHP 和 curl:
$report = 'report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip';
$cfile = new CURLFile(realpath($report),'application/zip',$report);
$PostData = array("reports[0]"=>$cfile);
但是如何通过 PowerShell 发送名为 reports[n]
的数组?
我试过的:
$url = "https://test.example.com/uploadAPI/upload.php"
$Source = "D:\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
$contentType = "multipart/form-data"
$Username = "ApiUploadKey"
$Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))}
$FileContens = get-content $Source
$PostData = @{"reports[0]" = $FileContens;}
#$reports = @($FileContens,'application/zip',$Source)
(Invoke-WebRequest -uri $url -Method POST -Headers $Headers -Body $PostData -ContentType $contentType).Content
#Invoke-RestMethod -uri $url -Method POST -Headers $Headers -Body $PostData -ContentType $contentType
这给了我一个我正在通过 not-a-report.
的回复编辑 2016-10-11
进一步调查让我想到这个 answer and this article。我尝试使用 boundary
:
clear
$url = "https://test.example.com/uploadAPI/upload.php"
$filename = "report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
$Source = "D:\"+$filename
$Username = "ApiUploadKey"
$Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))}
$FileContens = get-content $Source
$enc = [System.Text.Encoding]::GetEncoding("iso-8859-1")
$fileBin = [IO.File]::ReadAllBytes($Source)
$fileEnc = $enc.GetString($fileBin)
$boundary = [System.Guid]::NewGuid().ToString()
$LF = "`n"
$contentType = "multipart/form-data; boundary=--$boundary"
#$bodyLines = "--"+$boundary+$LF+"Content-Disposition: form-data; name=`"reports[]`"; filename=`""+$filename+"`""+$LF+$LF+"Content-Type: application/zip"+$LF+"--"+$boundary+"--"+$LF+$LF+$FileContens+$LF+"--"+$boundary
$bodyLines = (
"--$boundary", #I have tried reports[0] here too
"Content-Disposition: form-data; name=`"reports[]`"; filename=`"$filename`"", # filename= is optional
"Content-Type: application/zip",
"",
#$FileContens,
$fileEnc,
"--$boundary--"
) -join $LF
try {
#Invoke-WebRequest -Uri "https://asrp.cntd.ru/uploadAPI/" -Headers $Headers -WebSession $ws
Invoke-RestMethod -Uri $url -Body $bodyLines -Method POST -Headers $Headers -ContentType $contentType -TimeoutSec 50
}
catch [System.Net.WebException] {
Write-Error( "FAILED to reach '$url': $_" )
throw $_
}
但结果相同。
我也试过这个:
$wc = new-object System.Net.WebClient
$wc.Credentials = new-object System.Net.NetworkCredential("ApiUploadKey","")
ls "D:\*.zip" | foreach {
$wc.UploadFile('https://test.example.com/uploadAPI/upload.php', $_.FullName )
write-host $_.FullName
}
还有一个来自这个 answer 的解决方案:
Invoke-RestMethod -Uri $url -InFile $Source -ContentType "multipart/form-data" -Method POST -Headers $Headers
总是相同的响应 - 不是报告
编辑 2016-10-17
curl
我已经为 windows 下载了 curl
。并像这样使用它:
curl.exe https://test.example.com/uploadAPI/upload.php --user ApiUploadKey: --form "reports[0]=@d:\report_746_226255_20161010_1635.zip;type=application/zip"
这给了我:
[{"code" : 102 , "guid" : "{23CE9F7F-BEC8-4D4C-8AC3-2865CFA94FBD}" , "id" : "5804902bc73a2475177464", "filename" : "report_746_226255_20161010_1635.zip"}]
所以使用 curl 效果很好!
提琴手
不知道 post 的确切日志。
当我这样发送文件时:
POST https://test.example.com/uploadAPI/upload.php
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Host: test.example.com
Authorization: Basic ...
Content-Length: 21075175
请求正文:
---------------------------acebdf13572468
Content-Disposition: form-data; name="reports[]"; filename="report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip"
Content-Type: application/zip
<@INCLUDE *D:\report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip*@>
---------------------------acebdf13572468--
我得到了
HTTP/1.1 200 OK
Date: Mon, 17 Oct 2016 10:04:43 GMT
Server: Apache/2.4.20 (Win64) OpenSSL/1.0.2h PHP/7.0.6
X-Powered-By: PHP/7.0.6
Set-Cookie: SESSION_UPLOAD_ID=.....; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Connection: close
Content-Length: 193
Content-Encoding: none
Accept-Ranges: bytes
Content-Type: text/html; charset=UTF-8
[{"code" : 102 , "guid" : "{B67A9D89-368B-4665-96AC-77C2CA0F4766}" , "id" : "5804a23be4152532018928", "filename" : "report_746_226254_20161010_1320.{B67A9D89-368B-4665-96AC-77C2CA0F4766}.zip"}]
PHP 代码使用 Curl class 并将 $PostData 设置为:
$PostData = array("reports[0]"=>$cfile);
$PostData 是一个 key/value 对数组(在 PHP 中),键名为 Reports[0]。它只是一个字符串名称,表示键而不是数组元素。
在 curl 命令行工具中,我们可以使用以下命令上传文件:
curl.exe -F Reports[0]=@"I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://MyServer/uploader/api/upload
或者,它可能是(注意关键 Reports[0][2][3] ):
curl.exe -F Reports[0][2][3]=@"I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://asd-pc/uploader/api/upload
-F 为输入形式key/value对 注意文件名前的@ 在你的服务器上试一下,在Fiddler中查看session就知道curl和PHP是如何向服务器发送请求的。
对于具有其他键名的其他文件,例如 Reports1.
,您可以传递其他参数,例如 -H (header) -v(详细)-F我用我的网络服务器 运行 将文件上传到服务器的 Web Api2 服务测试了这段代码,运行 没问题。
所以,问题是:如何将该代码转换为与 Powershell 一起工作。
在 curl PHP 或命令行工具中,它会自动准备 Header 和请求 Body 以支持 Multipart/form-data.
的文件上传两个 Powershell 命令:Invoke-WebRequest 和 Invoke-RestMethod 都不知道如何格式化请求 body 以符合 Multipart/form-data 中给出的标准RFC Forms: multipart/form-data
您必须手动设置消息 body 然后调用您的调用
以下脚本使用 powershell 将文件上传到网络服务器。
我设置 Content-Type: application/octet-stream 以支持任何类型,包括 zip 文件。
function Upload-File ( $InFile,$Uri )
{
$Username = "ApiUploadKey"
$Headers = @{Authorization="Basic {0}" -f [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:" -f $Username)))}
$LF = "`n"
$fileName = Split-Path $InFile -leaf
$boundary = [System.Datetime]::Now.Ticks.ToString()
$binaryData = [System.IO.File]::ReadAllBytes($InFile)
$binaryEncoded=[System.Text.Encoding]::GetEncoding("iso-8859-1").GetString($binaryData)
$ContentType = "application/octet-stream"
$body = @"
--$boundary
Content-Disposition: form-data; name=`"Reports[0]`"; filename=`"$fileName`"
Content-Type: $ContentType
$LF
$binaryEncoded
--$boundary--
$LF
"@
try
{
return Invoke-RestMethod -Uri $Uri -Method Post -ContentType "multipart/form-data; boundary=$boundary" -Body $body -Headers $Headers
}
catch [Exception]
{
$PSCmdlet.ThrowTerminatingError($_)
}
}
#-- test the function ---------------------------------
cls
$uri = "http://MyServer/uploader/api/upload"
$filePath = "I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
$response = Upload-File -InFile $filePath -Uri $uri #-Credential $credentials
$response
fiddler
的输出session POST http://MyServer/uploader/api/upload HTTP/1.1
Authorization: Basic QXBpVXBsb2FkS2V5Og==
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 6.1; en-US) WindowsPowerShell/5.0.10586.117
Content-Type: multipart/form-data; boundary=636123339963709320
Host: MyServer
Content-Length: 379
Connection: Keep-Alive
--636123339963709320
Content-Disposition: form-data; name="Reports[0]"; filename="report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip"
Content-Type: application/octet-stream
xxxxxxxxxxxxxxxxxxxxxxxxxxxStream of byte sxxxxxxxxxxxxxxx
在上面的 session 数据中,您会看到 Reports[0] 的标题为 name
您可以在命令中使用相同的代码:Invoke-WebRequest