2016-08-25 6 views
1

Ситуации:Как передать массив с помощью веб-запроса

Мы собираем автоматически много сообщений от некоторых веб-служб (PowerShell скрипта, запускающих каждую ночь), и каждый день в ручном режиме (перетаскивание на веб-формы), эти отчеты загружаются в нашу БД.

Теперь наш ИТ-отдел предоставил нам API, который может обрабатывать эту работу без взаимодействия с пользователем.

Проблема:

Как было написано в сопроводительном письме (об этом API) он ждет reports[n] массив с файлом. Это может быть сделано с PHP и завитка:

$report = 'report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip'; 
$cfile = new CURLFile(realpath($report),'application/zip',$report); 
$PostData = array("reports[0]"=>$cfile); 

Но как отправить массив с именем reports[n] с помощью PowerShell?

То, что я пробовал:

$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 

Это дает мне ответ, который я передаю не-а-отчет.

EDIT 2016-10-11

Дальнейшие исследования довести меня до этого answer и этого 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 

Всегда же ответ - не отчет

EDIT 2016-10- 17

локон

Я скачал curl для окон. И использовать его как:

curl.exe https://test.example.com/uploadAPI/upload.php --user ApiUploadKey: --form "reports[0][email protected]:\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"}] 

Так с завитком он отлично работает!

стельку

Не знаю точно, что войти чтобы оставлять сообщения.

Когда я отправить файл, как это:

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"}] 
+0

try set content-type, -ContentType "multipart/form-data" –

+0

Я попробовал. Как видите, существует переменная '$ contentType'. Он использовался как '-ContentType $ contentType' в' Invoke-WebRequest'. Должен отредактировать мой вопрос. – gofr1

+0

TL; DR. Возможно, вы можете упростить вопрос. –

ответ

1

The PHP код использования Curl класса и набор $ PostData как:

$PostData = array("reports[0]"=>$cfile); 

$ PostData - это массив пары ключ/значение (в PHP), а ключ называется Reports [0]. это просто имя строки, представляющее ключ, а не элемент массива.

в завиток инструмент командной строки можно загрузить файл с помощью следующей команды:

curl.exe -F Reports[0][email protected]"I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://MyServer/uploader/api/upload 

или, может быть, (обратите внимание на ключевые доклады [0] [2] [3]):

curl.exe -F Reports[0][2][3][email protected]"I:\test\report_20160825.{8302F59C-E1E4-410F-BE37-A24CCD7E515E}.zip" http://asd-pc/uploader/api/upload 

-F для ввода пары ключ/значение формы Примечание @ перед именем файла Попробуйте на своем сервере и просмотрите сеанс в Fiddler, чтобы узнать, как curl и PHP отправляют запрос на сервер.

Вы можете передать другие параметры, такие как -H (header) -v (verbose) -F для других файлов с другим именем ключа, например, Reports 1.

Я проверил этот код с помощью моего веб-сервера, на котором запущен веб-сервис Api2, который загружает файл на сервер, и он работает нормально.

Итак, проблема заключается в следующем: как преобразовать этот код для работы с Powershell.

В curl либо PHP, либо инструмент командной строки, он автоматически подготавливает заголовок и тело запроса для загрузки файлов, которые поддерживают Multipart/form-data.

Оба Powershell команды: Invoke-WebRequest и Invoke-RestMethod не знают о том, как форматировать тело запроса, чтобы соответствовать стандарту MULTIPART/форм-данных, как указано в RFC Forms: multipart/form-data

Вы должны вручную установите тело сообщения, а затем вызовите свой вызов.

Следующий сценарий Загрузите файл на веб-сервер с помощью 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 

Выходной сессия стелька

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 

В данной сессии выше вы видите отчетов [0] называютсяName

Вы можете использовать один и тот же код, с помощью команды : Invoke-WebRequest