使用Delphi调用REST API发送附件时出现400错误的技术求助
Hey there! Let's figure out why your Delphi code is throwing a 400 Bad Request when sending attachments—since Postman works perfectly, the issue is almost certainly in how your request is structured in code. Here are the most likely fixes:
Key Issues to Check
1. You’re Using Raw Body Instead of Multipart Form-Data
Most file upload APIs expect requests to use multipart/form-data format (this is what Postman automatically uses when you add a file). Your current code is sending the file content as a raw body, which doesn’t match what the API expects.
2. Metadata in Headers vs. Form Parameters
You’re sending Filename and edi-document-qualifier as HTTP headers, but it’s far more common for APIs to expect these as form fields alongside the file. Postman might be passing them as form data without you noticing.
3. Unreliable Byte Array Conversion
Your FileToByteArray function uses manual pointer arithmetic, which can cause bugs (especially in 64-bit Delphi). Using TFileStream directly is safer and more maintainable.
Fixed Delphi Code Example
Here’s a revised version of your code that addresses these issues:
begin RespID := MyParams.Values['RespID']; // Set up the endpoint RESTrequest1.Resource := StringReplace(sendAttachments_endPoint, ':messageId', RespID, [rfReplaceAll]); RESTrequest1.Method := rmPOST; // Clear previous state RESTrequest1.Params.Clear; RESTrequest1.Body.ClearBody; // Reuse your working auth headers RESTrequest1.AddAuthParameter('api-key', authAPIkey, pkHTTPHEADER, [poDoNotEncode]); RESTrequest1.AddAuthParameter('Authorization', 'Bearer ' + JWToken, pkHTTPHEADER, [poDoNotEncode]); NbrOfAttach := StrToInt(MyParams.Values['attachments']); for idx := 1 to NbrOfAttach do begin AttachName := MyParams.Values['attach_' + IntToStr(idx)]; FileName := ExtractFileName(AttachName); // Use TFileStream for safe file reading var fs := TFileStream.Create(AttachName, fmOpenRead or fmShareDenyWrite); try // Set the correct content type for multipart uploads RESTrequest1.AddParameter('Content-Type', 'multipart/form-data', pkHTTPHEADER, [poDoNotEncode]); // Add the file as a form data part (check API docs for the correct field name, e.g., 'file' or 'attachment') var fileParam := RESTrequest1.Params.AddItem; fileParam.Name := 'file'; fileParam.Value := FileName; fileParam.Kind := pkREQUESTBODY; // Set correct content type based on file type if LowerCase(ExtractFileExt(AttachName)) = '.pdf' then fileParam.ContentType := 'application/pdf' else if LowerCase(ExtractFileExt(AttachName)) = '.jpeg' then fileParam.ContentType := 'image/jpeg'; fileParam.SetStream(fs, True); // Let RESTRequest manage stream cleanup // Add Filename as a form parameter (not header) var fileNameParam := RESTrequest1.Params.AddItem; fileNameParam.Name := 'Filename'; fileNameParam.Value := FileName; fileNameParam.Kind := pkREQUESTBODY; fileNameParam.Options := [poDoNotEncode]; // Add edi-document-qualifier as a form parameter (not header) var qualifierParam := RESTrequest1.Params.AddItem; qualifierParam.Name := 'edi-document-qualifier'; qualifierParam.Value := IntToStr(idx); qualifierParam.Kind := pkREQUESTBODY; qualifierParam.Options := [poDoNotEncode]; try RESTrequest1.Execute; REST_RepStatus := RESTresponse1.StatusCode; if REST_RepStatus = 200 then Writeln('Attachment ', idx, ' uploaded successfully!') else Writeln('Error uploading attachment ', idx, ': ', RESTresponse1.StatusText, ' (Code: ', REST_RepStatus, ')'); except on E: Exception do Writeln('Exception uploading attachment ', idx, ': ', E.Message); end; finally fs.Free; end; end; end;
Additional Tips for Debugging
- Compare Requests with Postman: Use a tool like Fiddler or Wireshark to capture the exact request Postman sends, then compare it to what your Delphi code sends. Look for differences in headers, form field names, or multipart boundaries.
- Check API Documentation: Confirm if the API expects specific form field names (e.g., maybe it uses
attachmentinstead offilefor the file parameter). - Test One Attachment at a Time: Simplify your loop to upload a single attachment first—this makes it easier to isolate issues.
内容的提问来源于stack exchange,提问作者Jean-Philippe




