Delphi 和 Walmart Bulk API 上传 - 内部服务器错误

Delphi and Walmart Bulk API Upload - Internal server error

我正在使用 Delphi XE5,我正在尝试使用批量 API 上传将项目发送到沃尔玛,但我正在努力与沃尔玛的服务器建立正确的连接。 我已经在这里检查了一些类似的问题,例如

最奇怪的是沃尔玛实际上接受了提要(我在提要列表中看到了)但是我收到内部服务器错误,然后是无意义的字符(可能是编码类型或只是一种错误)喜欢

(#$D#$A#F#[=26=]8B#8#0#0#0#0#0#0#3#$D'A±'#$D#[=26=]80'0'#$C#4'AU~'#2'v ?d'#[=26=]87#4'?'#1#[=26=]91'OE'#$E#[=26=]8A'O'#E'®?O?'##[=26=]91#$A#[=26=]91'M^'#$C'?;'#D'G'#$A'dR±U?oip?m'#A'AVS'#4#'R?iR'#B#[=26=]95'RO?}u'#0'enIjM'#0#0#0)

所以我使用 Indy IdHTTP 并尝试使用 TIdMultipartFormDataStream 并通过接收内部服务器自行创建有效载荷错误。 我想我以某种方式破坏了他们的解析器,因为如果我在开始时错过了一个 CR LF (#13#10),我会收到一个特定的错误

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><ns2:errors xmlns:ns2="http://walmart.com/"><ns2:error><ns2:code>SYSTEM_ERROR.GMP_GATEWAY_API</ns2:code><ns2:field>PDR-0012</ns2:field><ns2:description></ns2:description><ns2:info>System encountered some internal error.</ns2:info><ns2:severity>ERROR</ns2:severity><ns2:category>SYSTEM</ns2:category><ns2:causes/><ns2:errorIdentifiers/></ns2:error></ns2:errors>

如果我在末尾添加额外的 CRLF,则会收到另一个错误,指出请求中有多个提要。 所以我真的假设有什么东西使服务器/解析器 return 内部错误但我没有得到什么我再次重复提要实际上被接受然后在我收到的情况下由服务器处理这个错误。

这是一个带有我自己创建的负载的示例请求:

Headers

POST /v3/feeds?feedType=item HTTP/1.1
Content-Type: multipart/form-data; boundary=qwerty
Content-Length: 5077
WM_SVC.NAME: Walmart Marketplace
WM_QOS.CORRELATION_ID: {67F0E2F9-5EAC-4E8C-9C90-650D8F7B3B7A}
WM_SEC.TIMESTAMP: 1528364885909
WM_SEC.AUTH_SIGNATURE: nSHgqzPOtzSR4wJU+U/vQJk+rk6Ke2QwodTHjzkjau2BonXZxiU9e+3NFPzaat2OUyc+vr0jqRk0H0QWTSC21PrI87mvqei5UJCJwNiIx0zVjAGpxsnIuvtIKkQsBpuUAa8C6SjTiTpDRsNt4IOxrk+tLWxlwQubWVCV+009a6o=
WM_CONSUMER.ID: 16248274-1f53-4e6d-880e-b5417698b878
WM_CONSUMER.CHANNEL.TYPE: 0f3e4dd4-0514-4346-b39d-af0e00ea066d
Host: marketplace.walmartapis.com
Accept: application/xml, */*
Accept-Encoding: identity
Accept-Language: en-US
User-Agent: Mozilla/3.0 (compatible; Indy Library)

请求

--qwerty

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<MPItemFeed xmlns:ns2="http://walmart.com/">
    <MPItemFeedHeader>
        <version>3.1</version>
        <requestId>{694A5564-7E8E-46C7-B772-C944A8C9CF99}</requestId>
        <mart>WALMART_US</mart>
    </MPItemFeedHeader>
    <MPItem>
        <processMode>REPLACE_ALL</processMode>
        <sku>w-cc-a1-4pk-white-l</sku>
        <productIdentifiers>
            <productIdentifier>
                <productIdType>UPC</productIdType>
                <productId>192082276845</productId>
            </productIdentifier>
        </productIdentifiers>
        <MPProduct>
            <SkuUpdate>Yes</SkuUpdate>
            <productName>Caramel Cantina 4 Pack Sleeping Nursing Cross Front Maternity Bra (Large, White)</productName>
            <ProductIdUpdate>Yes</ProductIdUpdate>
            <category>
                <ClothingCategory>
                    <Clothing>
                        <shortDescription>Stretchy comfort cross front sleep bra by Caramel Cantina. Whether for nursing / maternity or for wearing as a sleep bra (or both nursing and sleep bras) - you&apos;ll experience a wire free regular back strap sleep bra. This mid-weight fabric but light support wireless bra is great for all day wear and comfort.  The straps are wider than a standard bra - offering a longer range of wear time.   Great for wearing indoors (ie when you&apos;re kicking around the home or going to bed). These are padless - most moms use their own favorite nursing pads with these (though no pads are included). The front cups have two layers of fabric to add a bit more support (though we still call them our light support comfort bra). The criss cross front style allows for easy access while nursing your baby. 92% Nylon 8% Spandex fabric washes up nicely.  Cool wash and cool dry. Hang dry for longer life. The straps narrowest point at the shoulders are 1.25-1.5 inches (depending on the size). The bras are super stretchy - if you&apos;re looking for something super supportive (ie - they pull you in really tight - more like a sports bra) these probably aren&apos;t what you&apos;re looking for.  Not recommended for heavy sports activity. Best worn for activities such as walking, sleeping, lounging, light activity, running errands, etc.</shortDescription>
                        <keyFeatures>
                            <keyFeaturesValue>4 Pack Includes 4 Bras of the Same Design - Color Option Above</keyFeaturesValue>
                            <keyFeaturesValue>Soft Cup - Front Double Layered - No padding - Wireless</keyFeaturesValue>
                            <keyFeaturesValue>Super Soft Sleep In Style Bra - Great for Nursing or Sleeping</keyFeaturesValue>
                            <keyFeaturesValue>Criss Cross Front Design Gives Easy Nursing Access</keyFeaturesValue>
                            <keyFeaturesValue>Regular Straps - Scoop Back Design - Strap Width 1.25-1.5 Inches Depending on Size</keyFeaturesValue>
                        </keyFeatures>
                        <brand>Caramel Cantina</brand>
                        <mainImageUrl>https://www.dancecheerskate.com/_inv/D54173DB8F934DB2A4C68D24FAC087F5/wm-cc-a1-4pk-white.jpg</mainImageUrl>
                        <productSecondaryImageURL>
                            <productSecondaryImageURLValue>https://www.dancecheerskate.com/_inv/D54173DB8F934DB2A4C68D24FAC087F5/wm-cc-a1-wht-m1.jpg</productSecondaryImageURLValue>
                        </productSecondaryImageURL>
                        <color>White</color>
                        <clothingSize>Large</clothingSize>
                        <variantGroupId>cc-a1-4pk-parent</variantGroupId>
                        <variantAttributeNames>
                            <variantAttributeName>color</variantAttributeName>
                            <variantAttributeName>clothingSize</variantAttributeName>
                        </variantAttributeNames>
                        <countryOfOriginTextiles>Imported</countryOfOriginTextiles>
                        <fabricCareInstructions>
                            <fabricCareInstruction>Machine wash cold gentle cycle with like colors. Hang Dry. Do Not Bleach. Do Not Iron.</fabricCareInstruction>
                        </fabricCareInstructions>
                        <multipackQuantity>1</multipackQuantity>
                        <countPerPack>4</countPerPack>
                        <count>4</count>
                        <pattern>Solid</pattern>
                        <material>Nylon; Spandex</material>
                        <gender>Female</gender>
                        <ageGroup>
                            <ageGroupValue>Adult</ageGroupValue>
                        </ageGroup>
                        <clothingSizeGroup>Maternity</clothingSizeGroup>
                        <isSet>No</isSet>
                        <requiresTextileActLabeling>Yes</requiresTextileActLabeling>
                        <clothingTopStyle>Sleep Bra</clothingTopStyle>
                        <upperBodyStrapConfiguration>Regular</upperBodyStrapConfiguration>
                        <braStyle>Nursing</braStyle>
                        <clothingStyle>Maternity</clothingStyle>
                        <clothingFit>Maternity</clothingFit>
                        <isMaternity>Yes</isMaternity>
                        <swatchImages>
                            <swatchImage>
                                <swatchVariantAttribute>color</swatchVariantAttribute>
                                <swatchImageUrl>https://www.dancecheerskate.com/_inv/D54173DB8F934DB2A4C68D24FAC087F5/wm-cc-a1-4pk-white.jpg</swatchImageUrl>
                            </swatchImage>
                        </swatchImages>
                    </Clothing>
                </ClothingCategory>
            </category>
        </MPProduct>
        <MPOffer>
            <price>25.00</price>
            <ShippingWeight>
                <measure>11.80</measure>
                <unit>lb</unit>
            </ShippingWeight>
            <ProductTaxCode>2038895</ProductTaxCode>
        </MPOffer>
    </MPItem>
</MPItemFeed>
--qwerty--

我得到的回复如下

HTTP/1.1 500 Internal Server Error
Method: null
URI: null
WM_CONSUMER.ID: 16248274-1f53-4e6d-880e-b5417698b878
WM_CONSUMER.INTIMESTAMP: 
WM_QOS.CORRELATION_ID: {67F0E2F9-5EAC-4E8C-9C90-650D8F7B3B7A}
WM_SEC.AUTH_TOKEN: 
WM_SEC.REFRESH_AUTH_TOKEN: 
WM_SVC.CLASS_NAME: com.walmart.services.impl.GMPGatewayService$$EnhancerBySpringCGLIB$$c88958a9
WM_SVC.ENV: prod
WM_SVC.INTIMESTAMP: 1528364905439
WM_SVC.METHOD_NAME: doPostMultiPart
WM_SVC.NAME: Walmart Marketplace
WM_SVC.OUTTIMESTAMP: 1528364905567
WM_SVC.SERVER_IP: 10.65.34.219
WM_SVC.SERVER_NAME: PartnerGMPService-5480119-4-96141283
WM_SVC.VERSION: 
X-Powered-By: soari-interceptors-4.4.4
Content-Type: text/plain
Cteonnt-Length: 77
Server: web
Content-Encoding: gzip
Content-Length: 89
Expires: Thu, 07 Jun 2018 09:48:25 GMT
Cache-Control: max-age=0, no-cache, no-store
Pragma: no-cache
Date: Thu, 07 Jun 2018 09:48:25 GMT
Connection: close

然后是上面的那些字符。 注意 Cteonnt-Length: 77 header, 这不是我的错字,它只是这样出现的。

根据支持,他们成功使用了以下 headers 并要求我使用它们,但我看不出我所做的有什么不同

WM_SVC.NAME:Walmart Marketplace
WM_QOS.CORRELATION_ID:123456abcdef
WM_SEC.AUTH_SIGNATURE:TnjevCf+voP9dmnafuCTFruwq6leBuAihSvag89WLieDRBsz7aULxgEqV71ZjIp572wVYPI07y6tdMutNLklDGwxvNdlJ2Q2xGvUIqjVPtqlhdcWvsmgqdpio7puQ4G03q1lReWzTquKecDEbB1ztH6ukj9F5rMe7d7PH8QkFsY=
WM_SEC.TIMESTAMP:1528152581896
WM_CONSUMER.ID:16248274-1f53-4e6d-880e-b5417698b878
WM_CONSUMER.CHANNEL.TYPE:0f3e4dd4-0514-4346-b39d-af0e00ea066d
Accept:application/xml
Host:marketplace.walmartapis.com
Content-Type:multipart/form-data

我已经与 eBay、Amazon、PayPal、Magento 等进行了成功的沟通,但显然我在这里遗漏了一些东西并且真的不知道如何解决它。

感谢您阅读本文,希望有人能提供线索。

编辑 我正在根据需要添加一些 Delphi 代码

版本 1 没有 TIdMultipartFormDataStream

function TdmSyncWallmart.CreateItemFeed(aIDPlatforms: String; aLastChanged,
  aCurrDate: TDateTime; var aReqID: String): TStringStream;
var
  aXML: TNativeXML;
  aNode: TXmlNode;
  aItemNode: TXmlNode;
  aCatNode: TXmlNode;
  aTmpNode: TXmlNode;

  aShortDesc: String;
  i: Integer;
  aIDItems: String;
begin
  Result := nil;

  dstListPlatformsSyncItemsWallmart.Close;
  dstListPlatformsSyncItemsWallmart.Parameters.ParamByName('@IDPlatforms').Value := aIDPlatforms;
  dstListPlatformsSyncItemsWallmart.Parameters.ParamByName('@LastChanged').Value := aLastChanged;
  dstListPlatformsSyncItemsWallmart.Parameters.ParamByName('@CurrDate').Value := aCurrDate;
  dstListPlatformsSyncItemsWallmart.Open;

  if dstListPlatformsSyncItemsWallmart.IsEmpty then
    Exit;

  aReqID := GenGuid;

  aXML := TNativeXml.CreateName('MPItemFeed');
  try
    aXML.Declaration.AttributeAdd('standalone', 'yes');
    aXML.Root.AttributeAdd('xmlns:ns2', 'http://walmart.com/');

    //Header
    aNode := aXML.Root.NodeNew('MPItemFeedHeader');
    with aNode.NodeNew('version') do
      Value := '3.1';
    with aNode.NodeNew('requestId') do
      Value := aReqID;
    with aNode.NodeNew('mart') do
      Value := 'WALMART_US';

  //... some code for generating the XML
    Result := TStringStream.Create;
    aXML.XmlFormat := xfReadable;

    Result.WriteString('--qwerty'#13#10#13#10{'Content-Disposition: form-data; filename="wallmartreq.xml"'#13#10}+aXML.WriteToString +'--qwerty--'#13#10);
    Result.Position := 0;

  finally
    aXML.Free;
  end;
end;

function TdmSyncWallmart.CreateHTTP(aContentType: String): TIdHTTP;
begin
  Result := TIdHTTP.Create(nil);
  Result.ConnectTimeout:=5000;
  Result.ReadTimeout:=20000;
  Result.ProtocolVersion:=pv1_1;
  Result.HTTPOptions := [hoForceEncodeParams, hoKeepOrigProtocol];
  Result.HandleRedirects:=True;
  Result.IOHandler := SSLHandler;
  Result.Request.Accept:='application/xml, */*';
  Result.Request.AcceptLanguage:='en-US';
  Result.Request.ContentType:=aContentType;
//  Result.Request.CharSet:='utf-8';
  Result.Intercept := IdLogEvent1;
end;

procedure TdmSyncWallmart.AddCustomHeaders(aHTTP: TIdHTTP; aSign,
  aTimeStamp: String);
begin
  aHTTP.Request.CustomHeaders.AddValue('WM_SVC.NAME', 'Walmart Marketplace');
  aHTTP.Request.CustomHeaders.AddValue('WM_QOS.CORRELATION_ID', GenGuid);
  aHTTP.Request.CustomHeaders.AddValue('WM_SEC.TIMESTAMP', aTimeStamp);
  aHTTP.Request.CustomHeaders.AddValue('WM_SEC.AUTH_SIGNATURE', aSign);
  aHTTP.Request.CustomHeaders.AddValue('WM_CONSUMER.ID', dstPlatformsUserName.AsString);
  aHTTP.Request.CustomHeaders.AddValue('WM_CONSUMER.CHANNEL.TYPE', dstPlatformsPassword.AsString);
end;

//some code for debugging purposes
procedure TdmSyncWallmart.IdLogEvent1Send(ASender: TIdConnectionIntercept;
  var ABuffer: TIdBytes);
var
  aList: TStringList;
begin
  aList := TStringList.Create;
  try
    aList.Text := BytesToString(ABuffer);
    aList.SaveToFile('e:\wm_req_txt.txt');
  finally
    aList.Free;
  end;
end;

procedure TdmSyncWallmart.IdLogEvent1Receive(ASender: TIdConnectionIntercept;
  var ABuffer: TIdBytes);
var
  aList: TStringList;
begin
  aList := TStringList.Create;
  try
    aList.Text := BytesToString(ABuffer);
    aList.SaveToFile('e:\wm_Resp.txt');
  finally
    aList.Free;
  end;
end;

实际调用

procedure TdmSyncWallmart.SendItems(aIDPlatforms: String; aLastChanged,
  aCurrDate: TDateTime);
var
  aSign, aTimeStamp: String;
  aURL: String;
  aHTTP: TIdHTTP;
  aRes: String;
  aStrm: TMemoryStream;
  aReqID: String;

  aXML: TNativeXml;
  aNode: TXmlNode;

  aErrMsg: String;
begin
  aURL := dstPlatformsURLAddress.AsString+'/v3/feeds?feedType=item';
  GenrateSignature(aSign, aTimeStamp, aURL, 'POST');
  if aSign = '' then
    Exit;

  aHTTP := CreateHTTP('multipart/form-data;boundary=qwerty');
  AddCustomHeaders(aHTTP, aSign, aTimeStamp);
  try
    aStrm := CreateItemFeed(aIDPlatforms, aLastChanged, aCurrDate, aReqID);
    if aStrm <> nil then
    begin
      try
        aRes := TIdURI.URLDecode(aHTTP.Post(aURL, aStrm));

        aXML := TNativeXml.Create(nil);
        try
          aXML.ReadFromString(aRes);

          aNode := aXML.Root.FindNode('feedId');

          cmdUpdFeedID.Parameters.ParamByName('ID').Value := aRes;
          cmdUpdFeedID.Parameters.ParamByName('FeedID').Value := aNode.Value;
          cmdUpdFeedID.Execute;
        finally
          aXML.Free;
        end;
      except
        on E:Exception do
        begin
          if E is EIdHTTPProtocolException then
            aErrMsg := E.Message + #13#10 + (E as EIdHTTPProtocolException).ErrorMessage
          else
            aErrMsg := E.Message;

          dmMain.InsLog(cLTError, aErrMsg, aIDPlatforms);

        end;
      end;
      aStrm.Free;
    end;
  finally
    aHTTP.Free;
  end;
end;

EDIT2

procedure TdmSyncWallmart.SendItems(aIDPlatforms: String; aLastChanged,
  aCurrDate: TDateTime);
var
  aSign, aTimeStamp: String;
  aURL: String;
  aHTTP: TIdHTTP;
  aRes: String;
  aStrm: TMemoryStream;
  aReqID: String;

  aXML: TNativeXml;
  aNode: TXmlNode;

  aErrMsg: String;

  aIdStream: TIdMultipartFormDataStream;
begin
  aURL := dstPlatformsURLAddress.AsString+'/v3/feeds?feedType=item';
  GenrateSignature(aSign, aTimeStamp, aURL, 'POST');
  if aSign = '' then
    Exit;

  aHTTP := CreateHTTP('multipart/form-data');
  AddCustomHeaders(aHTTP, aSign, aTimeStamp);
  try
    aStrm := TStringStream.Create();
    begin
      try
        aIdStream := TIdMultiPartFormDataStream.Create;
        aIdStream.AddFile('file', 'e:\wm_req.xml', 'multipart/form-data');
        aIdStream.Position := 0;
        astrm.LoadFromStream(aIdStream);

        aRes := TIdURI.URLDecode(aHTTP.Post(aURL, aStrm));

        aXML := TNativeXml.Create(nil);
        try
          aXML.ReadFromString(aRes);

          aNode := aXML.Root.FindNode('feedId');

          cmdUpdFeedID.Parameters.ParamByName('ID').Value := aRes;
          cmdUpdFeedID.Parameters.ParamByName('FeedID').Value := aNode.Value;
          cmdUpdFeedID.Execute;
        finally
          aXML.Free;
        end;
      except
        on E:Exception do
        begin
          if E is EIdHTTPProtocolException then
            aErrMsg := E.Message + #13#10 + (E as EIdHTTPProtocolException).ErrorMessage
          else
            aErrMsg := E.Message;

          dmMain.InsLog(cLTError, aErrMsg, aIDPlatforms);

        end;
      end;
      aStrm.Free;
    end;
  finally
    aHTTP.Free;
  end;
end;

这是发送的数据

----------060718213723831
Content-Disposition: form-data; name="file"; filename="wm_req.xml"
Content-Type: multipart/form-data
Content-Transfer-Encoding: binary

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<MPItemFeed xmlns:ns2="http://walmart.com/">
    <MPItemFeedHeader>
        <version>3.1</version>
        <requestId>{164726BF-288E-4953-A1DA-1EC7595C5725}</requestId>
        <mart>WALMART_US</mart>
    </MPItemFeedHeader>
    <MPItem>
        <processMode>REPLACE_ALL</processMode>
        <sku>w-cc-a1-4pk-white-l</sku>
        <productIdentifiers>
            <productIdentifier>
                <productIdType>UPC</productIdType>
                <productId>192082276845</productId>
            </productIdentifier>
        </productIdentifiers>
        <MPProduct>
        ..... the other part of the XML
        </MPProduct>
        <MPOffer>
            <price>25.00</price>
            <ShippingWeight>
                <measure>11.80</measure>
                <unit>lb</unit>
            </ShippingWeight>
            <ProductTaxCode>2038895</ProductTaxCode>
        </MPOffer>
    </MPItem>
</MPItemFeed>
----------060718213723831--

拦截部分捕获的返回数据与已经post再次Cteonnt-Length的数据相同:77 header ,但我想如果我成功读取 gzip 数据,我会遇到一个可以转发给支持人员的错误。

HTTP/1.1 500 Internal Server Error
Method: null
URI: null
WM_CONSUMER.ID: 16248274-1f53-4e6d-880e-b5417698b878
WM_CONSUMER.INTIMESTAMP: 
WM_QOS.CORRELATION_ID: {CB0208AB-2135-4A12-B45F-DD2889273971}
WM_SEC.AUTH_TOKEN: 
WM_SEC.REFRESH_AUTH_TOKEN: 
WM_SVC.CLASS_NAME: com.walmart.services.impl.GMPGatewayService$$EnhancerBySpringCGLIB$ca3f3b6
WM_SVC.ENV: prod
WM_SVC.INTIMESTAMP: 1528396669253
WM_SVC.METHOD_NAME: doPostMultiPart
WM_SVC.NAME: Walmart Marketplace
WM_SVC.OUTTIMESTAMP: 1528396669365
WM_SVC.SERVER_IP: 10.65.34.2
WM_SVC.SERVER_NAME: PartnerGMPService-5480119-1-96141274
WM_SVC.VERSION: 
X-Powered-By: soari-interceptors-4.4.4
Content-Type: text/plain
Cteonnt-Length: 77
Server: web
Content-Encoding: gzip
Content-Length: 89
Vary: Accept-Encoding
Expires: Thu, 07 Jun 2018 18:37:49 GMT
Cache-Control: max-age=0, no-cache, no-store
Pragma: no-cache
Date: Thu, 07 Jun 2018 18:37:49 GMT
Connection: close

EDIT3

对于我的 Edit1,我根本没有添加 Content-Disposition(它已被注释)- 有太多的测试我把它留在了我的 post 在这里,很抱歉造成混淆。

对于 Edit2 - 感谢您指出这一点,实际上我在没有转换为 TStringStream 的情况下进行了第一次测试,但我想看看它们究竟发生了什么。

反正现在我直接用了TIdMultipartFormDataStream,改了代码就这样

    aIdStream := TIdMultiPartFormDataStream.Create;
    with aIdStream.AddFile('xml', 'e:\wm_req.xml', 'application/xml') do
    begin
      FileName := '';
      //ContentType := '';
      FileName := 'wmreq.xml';//somewhere I think I saw that only letters are allowed here
    end;
    aIdStream.Position := 0;

    aStrm := TMemoryStream.Create;

    //aRes := TIdURI.URLDecode(aHTTP.Post(aURL, aIdStream));
    aHTTP.Post(aURL, aIdStream, aStrm);

多亏了 Remy,我添加了 TIdCompressorZLib,现在我得到了有意义的错误:

HTTP/1.1 500 Internal Server Error No message body writer has been found for response class FeedAcknowledgement.

我想这是他们的,不是我的,需要和他们核实一下。

EDIT4 解决方案

好吧,不管是否疯狂,也许是我的问题,但是一旦雷米说我不要求压缩答案并且他们给我发送了这样的答案,我决定将 // Result.Request.Accept:='application/xml, */*'; 更改为仅 // Result.Request.Accept:='application/xml'; 并且一切开始正常工作!事实上,拥有 */* 意味着我正在接受一切,不是吗?无论您使用的是 TIdMultipartFormDataStream 还是 body 是手动准备的,它都可以正常工作。谢谢雷米的不同观点,另一双眼睛总是有帮助的。疯了...一周的愚蠢测试!

在您的第一次编辑中,您没有正确填充 TStringStream。改用这个:

Result.WriteString('--qwerty'#13#10{'Content-Disposition: form-data; name="file"; filename="wallmartreq.xml"'#13#10}#13#10 + aXML.WriteToString + #13#10'--qwerty--'#13#10);

在您的第二次编辑中,您向 TIdMultipartFormDataStream.AddFile() 提供了错误的 ContentType。您需要使用 application/xml 而不是 multipart/form-data:

aIdStream.AddFile('file', 'e:\wm_req.xml', 'application/xml');

或者,将 ContentType 留空(在这种情况下,将使用 application/octet-stream):

aIdStream.AddFile('file', 'e:\wm_req.xml');

如果您根本不想发送 ContentType,可以将 TIdFormDataField.ContentType 属性 设置为空字符串:

with aIdStream.AddFile('file', 'e:\wm_req.xml') do
begin 
  FileName := ''; // needed so ContentType setter will not use a default value...
  ContentType := '';
  FileName := 'wm_req.xml'; // or whatever you want, or leave blank...
end;

但是,更重要的是,您不再为 TIdHTTP.Request.ContentType header 指定 boundary 属性。事实上,您根本不应该将 TIdMultipartFormDataStream 保存到 TStringStream 然后发布 TStringStream。您应该改为发布 TIdMultipartFormDataStream 本身。这将自动将 TIdHTTP.Request.ContentType 设置为 multipart/form-data,并为其提供正确的 boundary 属性(其值由 TIdMultipartFormDataStream 生成):

aHTTP.Post(aURL, aIdStream)

现在,话虽如此,在这两种情况下,您都需要删除对 TIdHTTP.Post() 的 return 值的 TIdURI.URLDecode() 调用。服务器应该向您发送 raw XML,而不是 URL-encoded XML,因此您需要处理 XML as-is 而不是 URL-decode。

此外,由于 XML 在技术上是二进制数据,可以在 任何 字符集中编码,HTTP 响应中可能存在也可能不存在 header s,你应该让你的XML解析器处理XML完全,因为它是由服务器发送的。为此,请使用 TIdHTTP.Post() 的重载版本填充 TStream 而不是 return 和 String。让它接收服务器的 XML 到 TMemoryStream,然后将该流加载到您的解析器(TNativeXml 有一个 LoadFromStream() 方法)。


最后,您显示服务器的响应有一个 Content-Encoding: gzip 响应 header,但我没有看到您将任何 object 分配给 TIdHTTP.Compressor 属性,或手动设置 TIdHTTP.Request.AcceptEncoding 属性,因此服务器不应以压缩格式发送响应 body,因为您不需要该格式。如果没有分配 CompressorTIdHTTP 将不会自动解压缩数据。

如果服务器真的在未经询问的情况下发送压缩数据,那是服务器端的错误,您应该向沃尔玛报告。