Загрузить, чтобы пропустить веб-сервер - PullRequest
0 голосов
/ 31 мая 2019

Я пытаюсь загрузить файл JSON на веб-сервер SKIP (getskip.com) и получаю сообщение об ошибке сокета 10054. Они не очень хорошо дают примеры того, как, так как считают, что все используют cUrl, но мы все еще используем Delphi XE6 с Indy.

Вот что они предоставили.

Для Java, используя OK HTTP:

OkHttpClient client = new OkHttpClient();

MediaType mediaType = MediaType.parse("multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
RequestBody body = RequestBody.create(mediaType, "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"path\"; filename=\"<<file_name>>\"\r\nContent-Type: application/vnd.novadigm.ext\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n[{\"file_key\": \"path\", \"store_id\"::<<store_id>>}]\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
Request request = new Request.Builder()
  .url("https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json")
  .post(body)
  .addHeader("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
  .addHeader("Authorization", "Bearer <<api_user_token>>")
  .addHeader("Content-Type", "application/x-www-form-urlencoded")
  .addHeader("User-Agent", "PostmanRuntime/7.13.0")
  .addHeader("Accept", "*/*")
  .addHeader("Cache-Control", "no-cache")
  .addHeader("Postman-Token", "de9932d2-bda0-4df6-8a9a-e2d4f74c2048,d59a9861-1a65-471a-8ada-6e025e985dca")
  .addHeader("Host", "upload.goskip.com:8080")
  .addHeader("accept-encoding", "gzip, deflate")
  .addHeader("content-length", "407")
  .addHeader("Connection", "keep-alive")
  .addHeader("cache-control", "no-cache")
  .build();

Response response = client.newCall(request).execute();

Java с использованием Unirest:

HttpResponse<String> response = Unirest.post("https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json")
  .header("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW")
  .header("Authorization", "Bearer <<api_user_token>>")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .header("User-Agent", "PostmanRuntime/7.13.0")
  .header("Accept", "*/*")
  .header("Cache-Control", "no-cache")
  .header("Postman-Token", "de9932d2-bda0-4df6-8a9a-e2d4f74c2048,d1ea454e-594c-4746-9de7-e813377ff095")
  .header("Host", "upload.goskip.com:8080")
  .header("accept-encoding", "gzip, deflate")
  .header("content-length", "407")
  .header("Connection", "keep-alive")
  .header("cache-control", "no-cache")
  .body("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"path\"; filename=\"<<file_name>>\"\r\nContent-Type: application/vnd.novadigm.ext\r\n\r\n\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n[{\"file_key\": \"path\", \"store_id\":<<store_id>>}]\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--")
  .asString();

PHP с использованием HttpRequest:

<?php

$request = new HttpRequest();
$request->setUrl('https://upload.goskip.com:8080/v2/backoffice/files/pricebook');
$request->setMethod(HTTP_METH_POST);

$request->setQueryData(array(
  'type' => 'json'
));

$request->setHeaders(array(
  'cache-control' => 'no-cache',
  'Connection' => 'keep-alive',
  'content-length' => '407',
  'accept-encoding' => 'gzip, deflate',
  'Host' => 'upload.goskip.com:8080',
  'Postman-Token' => 'de9932d2-bda0-4df6-8a9a-e2d4f74c2048,c7acbc0a-6450-43d1-b4ca-bc2a56cebc4e',
  'Cache-Control' => 'no-cache',
  'Accept' => '*/*',
  'User-Agent' => 'PostmanRuntime/7.13.0',
  'Content-Type' => 'application/x-www-form-urlencoded',
  'Authorization' => 'Bearer <<api_user_token>>',
  'content-type' => 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
));

$request->setBody('------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="path"; filename="<<file_name>>"
Content-Type: application/vnd.novadigm.ext


------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="data"

[{"file_key": "path", "store_id"::<<store_id>>}]
------WebKitFormBoundary7MA4YWxkTrZu0gW--');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}

Вот что я попробовал в Инди. Я вставил файл JSON в заметку на форме:

function TFormJsonWrite.HTTPPost: String;
var
  JsonToSend : TStringStream;
  Response: String;
  IdHTTP1: TIdHTTP;
  IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
begin
  IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create;
  IdHTTP1 := TIdHTTP.Create;
  IdHTTP1.Request.CharSet := 'utf-8';

  JsonToSend := TStringStream.Create(memolog.text, TEncoding.UTF8);
  IdHTTP1.Request.ContentDisposition := 'form-data; name=[{"file_key":''' + memolog.text + ''', "store_id"::001}]------WebKitFormBoundary7MA4YWxkTrZu0gW--';
  IdHTTP1.Request.UserAgent := 'Mozilla/3.0 (compatible; Indy Library)';
  IdHTTP1.Request.ContentType := 'multipart/form-data';
  IdHTTP1.Request.Accept := '*/*';
  IdHTTP1.Request.AcceptEncoding := 'gzip,deflate';
  IdHTTP1.Request.ContentLength := -1;
  IdHTTP1.Request.CacheControl := 'no-cache';
  IdHTTP1.Request.Connection := 'keep-alive';
  IdHTTP1.Request.BasicAuthentication := false;
  IdHTTP1.Request.Host := 'upload.goskip.com:8080';
  IdHTTP1.Request.CustomHeaders.Clear;
  IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer eyJhbGc.......................';
  IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := 'de9932d2-bda0-4df6-8a9a-e2d4f74c2048,d59a9861-1a65-471a-8ada-6e025e985dca';
  IdHTTP1.ReadTimeout := 50000;
  IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
  IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;
  Response := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', JsonToSend);
  HTTPPost := Response;
  JsonToSend.Free;
  IdHTTP1.Free;
end;

локон

Kim@KIMNEW MINGW64 ~
$ curl -F "file=@"C:/mydata/Items-114946.json -H "authorization:Bearer eyJ........................." https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json&store_id=001
[1] 13296
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
Kim@KIMNEW MINGW64 ~
100  951k  100    53  100  951k     53   968k  0:00:01 --:--:--  0:00:01  967k{"message":"#/data: null value where array expected"}

Они обновляют все свои конечные точки, это последнее, что я получил.

curl -X POST   'https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json'   -H 'Authorization: Bearer <api_user_token>' -F path=@<path_to_first_file>   -F path1=@<path_to_second_file>   -F 'data=[{"file_key":"path","store_id":<store_id_for_first_file>},{"file_key":"path1","store_id":<store_id_for_second_file>}]'

1 Ответ

2 голосов
/ 31 мая 2019

Ваш код Delphi неверен.

Вы устанавливаете неправильный заголовок Content-Disposition на неправильное значение.

Вы публикуете данные JSON как есть, не помещая их вMIME вообще.

НЕ устанавливайте свойство TIdHTTP.Request.AcceptEncoding вручную.Вы не настраиваете TIdHTTP для включения поддержки сжатия, но вы даете серверу разрешение отправлять сжатые ответы, которые TIdHTTP не сможет распаковать для вас.

Правильно способ отправки multipart/form-data запроса с использованием TIdHTTP заключается в использовании перегруженного метода Post(), который принимает TIdMultipartFormDataStream в качестве ввода, например:

function TFormJsonWrite.HTTPPost: String;
var
  JsonToSend : String;
  IdHTTP1: TIdHTTP;
  IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
  PostData: TIdMultipartFormDataStream;
begin
  JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';

  IdHTTP1 := TIdHTTP.Create;
  try
    IdHTTP1.ReadTimeout := 50000;

    IdHTTP1.Request.BasicAuthentication := false;
    IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
    IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';

    IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
    IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
    IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;

    PostData := TIdMultipartFormDataStream.Create;
    try
      PostData.AddFormField('path', '', '', 'application/vnd.novadigm.ext').FileName := '<<file_name>>';
      PostData.AddFormField('data', JsonToSend, 'utf-8', 'application/json').ContentTransfer := '8bit';

      Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
    finally
      PostData.Free;
    end;
  finally
    IdHTTP1.Free;
  end;
end;

Если случайноу сервера есть проблемы с тем, как TIdMultipartFormDataStream форматирует данные MIME (т. е. если сервер отклоняет заголовки MIME Content-Type и / или Content-Transfer-Encoding, которые генерируются TIdMultipartFormDataStream для каждого поля MIME, поскольку он еще не соответствуетв RFC 7578 , который используется в HTML5), вы можете отформатировать данные MIME вручную, чтобы точно соответствовать образцам SKIP, например:

function TFormJsonWrite.HTTPPost: String;
var
  JsonToSend : String;
  IdHTTP1: TIdHTTP;
  IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
  PostData: TStringStream;
begin
  JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';

  IdHTTP1 := TIdHTTP.Create;
  try
    IdHTTP1.ReadTimeout := 50000;

    IdHTTP1.Request.ContentType := 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW';
    IdHTTP1.Request.BasicAuthentication := false;
    IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
    IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';

    IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
    IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
    IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;

    PostData := TStringStream.Create(
      '------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL +
      'Content-Disposition: form-data; name="path"; filename="<<file_name>>"' + EOL +
      'Content-Type: application/vnd.novadigm.ext' + EOL +
      EOL +
      EOL +
      '------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL +
      'Content-Disposition: form-data; name="data"' + EOL +
      EOL +
      JsonToSend + EOL +
      '------WebKitFormBoundary7MA4YWxkTrZu0gW--',
      TEncoding.UTF8
    );
    try
      Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
    finally
      PostData.Free;
    end;
  finally
    IdHTTP1.Free;
  end;
end;

ОБНОВЛЕНИЕ : основываясь на предоставленных вами новых командах curl, показанные вами оригинальные примеры не соответствуют командам.Вместо этого попробуйте что-то вроде этого:

function TFormJsonWrite.HTTPPost: String;
var
  JsonToSend : String;
  IdHTTP1: TIdHTTP;
  IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
  PostData: TIdMultipartFormDataStream;
begin
  JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';

  IdHTTP1 := TIdHTTP.Create;
  try
    IdHTTP1.ReadTimeout := 50000;

    IdHTTP1.Request.BasicAuthentication := false;
    IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
    IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';

    IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
    IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
    IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;

    PostData := TIdMultipartFormDataStream.Create;
    try
      PostData.AddFile('path', '<<path_to_file>>').ContentTransfer := 'binary';
      PostData.AddFormField('data', JsonToSend, 'utf-8', 'application/json').ContentTransfer := '8bit';

      Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
    finally
      PostData.Free;
    end;
  finally
    IdHTTP1.Free;
  end;
end;

Или:

function TFormJsonWrite.HTTPPost: String;
var
  JsonToSend : String;
  IdHTTP1: TIdHTTP;
  IdSSLIOHandlerSocketOpenSSL2: TIdSSLIOHandlerSocketOpenSSL;
  PostData: TMemoryStream;
  FS: TIdReadFileExclusiveStream;
begin
  JsonToSend := '[{"file_key": "path", "store_id": <<store_id>>}]';

  IdHTTP1 := TIdHTTP.Create;
  try
    IdHTTP1.ReadTimeout := 50000;

    IdHTTP1.Request.ContentType := 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW';
    IdHTTP1.Request.BasicAuthentication := false;
    IdHTTP1.Request.CustomHeaders.Values['Authorization'] := 'Bearer ...';
    IdHTTP1.Request.CustomHeaders.Values['Postman-Token'] := '...';

    IdSSLIOHandlerSocketOpenSSL2 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
    IdSSLIOHandlerSocketOpenSSL2.SSLOptions.Method := sslvTLSv1_2;
    IdHTTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL2;

    PostData := TMemoryStream.Create;
    try
      WriteStringToStream(PostData, '------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL);
      WriteStringToStream(PostData, 'Content-Disposition: form-data; name="path"; filename="<<file_name>>"' + EOL);
      WriteStringToStream(PostData, 'Content-Type: ' + GetMIMETypeFromFile('<<file_name>>') + EOL);
      WriteStringToStream(PostData, 'Content-Transfer-Encoding: binary' + EOL);
      WriteStringToStream(PostData, EOL);

      FS := TIdReadFileExclusiveStream.Create('<<path_to_file>>', fmOpenRead or fmShareDenyWrite);
      try
        PostData.CopyFrom(FS, 0);
      finally
        FS.Free;
      end;

      WriteStringToStream(PostData, EOL);
      WriteStringToStream(PostData, '------WebKitFormBoundary7MA4YWxkTrZu0gW' + EOL);
      WriteStringToStream(PostData, 'Content-Disposition: form-data; name="data"' + EOL);
      WriteStringToStream(PostData, EOL);
      WriteStringToStream(PostData, JsonToSend + EOL, IndyTextEncoding_UTF8);
      WriteStringToStream(PostData, '------WebKitFormBoundary7MA4YWxkTrZu0gW--');

      PostData.Position := 0;

      Result := IdHTTP1.Post('https://upload.goskip.com:8080/v2/backoffice/files/pricebook?type=json', PostData);
    finally
      PostData.Free;
    end;
  finally
    IdHTTP1.Free;
  end;
end;
...