简体   繁体   English

使用 Delphi 和 REST api 发送文件

[英]Sending files using Delphi and REST api

I need to write a Delphi program to test REST api. There are two parts: the first is sending messages (JSon, Edifact or pure text, which we call business messages).我需要写一个Delphi的程序来测试REST api。有两部分:首先是发送消息(JSON,Edifact或者纯文本,我们称之为业务消息)。 After some trial and error, I'm able to send messages.经过反复试验,我可以发送消息了。 But I have problems with the second part, which is to send files as attachment (mainly pdf and jpeg).但是我对第二部分有问题,即将文件作为附件发送(主要是 pdf 和 jpeg)。 I test the API with POSTMAN without any problem, but when I try to "translate" the request in Delphi, I get a 400 Bad request status.我用 POSTMAN 测试 API 没有任何问题,但是当我尝试“翻译”Delphi 中的请求时,我得到一个 400 Bad 请求状态。 Here is my code:这是我的代码:

begin
  //the 'RespID' is generated by the API when sending the business message and is needed to link the message with the attachment(s)
  RespID := MyParams.Values['RespID'];
  // sendAttachments_endPoint =/messages/:messageId/attachments
  RESTrequest1.Resource := StringReplace(sendAttachments_endPoint, ':messageId', RespID, [rfReplaceAll]);
  NbrOfAttach := StrToInt(MyParams.Values['attachments']);

  for idx := 1 to NbrOfAttach do
    begin
      AttachName := MyParams.Values['attach_' + IntToStr(idx)];
      FileName := ExtractFileName(AttachName);

      ABytes := FileToByteArray(AttachName);
      SetString(TmpStr, PAnsiChar(@ABytes[0]), Length(ABytes));

      with RESTrequest1 do
        begin
          Body.ClearBody;
          Params.Clear;

          RESTrequest1.AddBody(TmpStr);

          //authentication works quite well and is used as is in other programs
          AddAuthParameter('api-key', authAPIkey, pkHTTPHEADER, [poDoNotEncode]);
          AddAuthParameter('Authorization', 'Bearer ' + JWToken, pkHTTPHEADER, [poDoNotEncode]);

          AParameter := RESTrequest1.Params.AddItem;
          //Filename parameter is required in the API header...
          AParameter.Name := 'Filename';
          AParameter.Value := FileName;
          AParameter.Kind := pkHTTPHEADER;

          AParameter := RESTrequest1.Params.AddItem;
          // as well as the edi-document-qualifier
          AParameter.Name := 'edi-document-qualifier';
          AParameter.Value := IntToStr(idx);
          AParameter.Kind := pkHTTPHEADER;
          AParameter.Options := [poDoNotEncode];

          AParameter := RESTrequest1.Params.AddItem;
          AParameter.Name := 'Content-Type';
          AParameter.Value := 'application/pdf';
          AParameter.Kind := pkHTTPHEADER;
          AParameter.Options := [poDoNotEncode];

          try
            Execute;
            REST_RepStatus := RESTresponse1.StatusCode;
            // REST_RepStatus = 400
            ...

The function FileToByteArray looks like this function FileToByteArray 看起来像这样

function FileToByteArray(const FileName: WideString): TArray<Byte>;
const
  BLOCK_SIZE = 1024;
var
  BytesRead, BytesToWrite, Count: integer;
  F: file of Byte;
  pTemp: Pointer;
begin
  AssignFile(F, FileName);
  Reset(F);
  try
    Count := FileSize(F);
    SetLength(Result, Count);
    pTemp := @Result[0];
    BytesRead := BLOCK_SIZE;
    while (BytesRead = BLOCK_SIZE) do
      begin
        BytesToWrite := Min(Count, BLOCK_SIZE);
        BlockRead(F, pTemp^, BytesToWrite, BytesRead);
        pTemp := Pointer(LongInt(pTemp) + BLOCK_SIZE);
        Count := Count - BytesRead;
      end;
  finally
    CloseFile(F);
  end;
end;

instead of passing the content of the file as a string, I've tried to use a stream我没有将文件的内容作为字符串传递,而是尝试使用 stream

var
fs: TFileStream;
...
fs := TFileStream.Create(AttachName, fmOpenRead);
...
RESTrequest1.AddBody(fs);

but no way, I always get a Bad Request但没办法,我总是收到 Bad Request

To send files through Delphi REST Client, you can just use the TRESTRequest's method "AddFile".要通过 Delphi REST 客户端发送文件,您可以使用 TRESTRequest 的方法“AddFile”。 With this simple method, you only need to specify the path to your file on the local drive or storage and his content type (there is a wide list of MIME types), without any need to do additional steps by yourself like: encoding the file to Base64, creating parameters with the kind "pkFILE", or setting the request's content type to "Multipart/formdata".使用这种简单的方法,您只需要指定文件在本地驱动器或存储上的路径及其内容类型(有多种 MIME 类型),而无需自己执行其他步骤,例如:对文件进行编码到 Base64,创建类型为“pkFILE”的参数,或将请求的内容类型设置为“Multipart/formdata”。 There is also an overloaded version of this method where you can specify a unique name for identifying the file within the request content (similar to the ''Name'' attribute in an HTML form's ''Input'' elements), so as you can send multiple files with different content types in the same request without risk of overwriting.此方法还有一个重载版本,您可以在其中指定一个唯一名称来标识请求内容中的文件(类似于 HTML 表单的“输入”元素中的“名称”属性),这样您就可以在同一个请求中发送具有不同内容类型的多个文件而没有被覆盖的风险。 You can get further information about this method in the DocWiki.您可以在 DocWiki 中获得有关此方法的更多信息。

And on the server side, you have to set the logic for retrieving and saving the file and even sending responses about the uploading result (whether it was done successfully or failed).在服务器端,您必须设置检索和保存文件的逻辑,甚至发送有关上传结果的响应(无论上传成功还是失败)。

Here is a minimal code example for sending a Word document (check the content type):这是发送 Word 文档的最小代码示例(检查内容类型):

procedure TForm1.BtnSendFileClick(Sender: TObject);
begin
  try
    try
    RESTRequest1.Method := TRESTRequestMethod.rmPOST;
    RESTRequest1.AddFile('File1', 'C:\Doc1.docx', TRESTContentType.ctAPPLICATION_VND_OPENXMLFORMATS_OFFICEDOCUMENT_WORDPROCESSINGML_DOCUMENT);
    RESTRequest1.Execute;
    except
    ShowMessage('Uploading failed');
    end;
  finally
  ShowMessage(RESTRequest1.Response.Content); //here our example server script will print "Uploaded successfully"
  end;
end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM