You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lazarus中用TFPHTTPClient发送SOAP Envelope遇流读取错误求助

问题描述

我正在开发客户端应用,需通过XML SOAP Envelope与服务端通信。尝试使用TFPHTTPClient实现该功能,已在窗体上放置按钮、Memo1(展示XML代码)和Memo2(展示服务端响应),但发送请求时收到「Stream read error」错误。有意思的是,将Memo1中的XML代码复制到SoapUI中执行可正常运行,我的代码如下:

procedure TForm1.Button2Click(Sender: TObject);
var
  FPHTTPClient: TFPHTTPClient;
  SL: TStringList;
  Str: String;

begin
  FPHTTPClient := TFPHTTPClient.Create(nil);
  try
    FPHTTPClient.AllowRedirect := True;
    FPHTTPClient.KeepConnection:=True;
    FPHTTPClient.AddHeader('Content-Type','application/soap+xml;charset=utf-8');
    FPHTTPClient.AddHeader('User-Agent','Apache-HttpClient/4.5.5 (Java/16.0.1)');


    SL := TStringList.Create;

    try
      SL.Add('<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07"> ');
      SL.Add('<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">');
      SL.Add('<wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To>');
      SL.Add('<wsa:Action>http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj</wsa:Action>');
      SL.Add('</soap:Header>');
      SL.Add('<soap:Body>');
      SL.Add('<ns:Zaloguj>');
      SL.Add('<ns:pKluczUzytkownika>abcde12345abcde12345</ns:pKluczUzytkownika>');
      SL.Add('</ns:Zaloguj>');
      SL.Add('</soap:Body>');
      SL.Add('</soap:Envelope>');



Memo1.Lines.BeginUpdate;
Memo1.Lines := SL;
Memo1.Lines.EndUpdate;
      try

        Str:=FPHTTPClient.FormPost('https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc',SL);
                    //ShowMessage(Str);

Memo2.text := Str;

      except
        on E: exception do
          ShowMessage(E.Message);
      end;
    finally
      SL.Free;
    end;
  finally
    FPHTTPClient.Free;
  end;
end;

解决方案

核心问题是误用了FormPost方法,它是专门用来发送application/x-www-form-urlencoded类型的表单数据的,会把TStringList的内容解析成key=value格式拼接,完全不符合SOAP XML的传输要求。需要改用Post方法直接发送原始XML文本,同时修正内存引用问题:

procedure TForm1.Button2Click(Sender: TObject);
var
  FPHTTPClient: TFPHTTPClient;
  SL: TStringList;
  Str: String;
begin
  FPHTTPClient := TFPHTTPClient.Create(nil);
  try
    FPHTTPClient.AllowRedirect := True;
    FPHTTPClient.KeepConnection := True;
    FPHTTPClient.AddHeader('Content-Type', 'application/soap+xml;charset=utf-8');
    FPHTTPClient.AddHeader('User-Agent', 'Apache-HttpClient/4.5.5 (Java/16.0.1)');

    SL := TStringList.Create;
    try
      SL.Add('<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://CIS/BIR/PUBL/2014/07"> ');
      SL.Add('<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">');
      SL.Add('<wsa:To>https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc</wsa:To>');
      SL.Add('<wsa:Action>http://CIS/BIR/PUBL/2014/07/IUslugaBIRzewnPubl/Zaloguj</wsa:Action>');
      SL.Add('</soap:Header>');
      SL.Add('<soap:Body>');
      SL.Add('<ns:Zaloguj>');
      SL.Add('<ns:pKluczUzytkownika>abcde12345abcde12345</ns:pKluczUzytkownika>');
      SL.Add('</ns:Zaloguj>');
      SL.Add('</soap:Body>');
      SL.Add('</soap:Envelope>');

      // 用Assign安全复制内容,避免SL释放后Memo1内容失效
      Memo1.Lines.BeginUpdate;
      try
        Memo1.Lines.Assign(SL);
      finally
        Memo1.Lines.EndUpdate;
      end;

      try
        // 改用Post发送原始XML文本
        Str := FPHTTPClient.Post('https://wyszukiwarkaregontest.stat.gov.pl/wsBIR/UslugaBIRzewnPubl.svc', SL.Text);
        Memo2.Text := Str;
      except
        on E: Exception do
          ShowMessage(E.Message);
      end;
    finally
      SL.Free;
    end;
  finally
    FPHTTPClient.Free;
  end;
end;

关键修正说明

  1. 替换请求方法:把FormPost改为Post,直接传递SL.Text作为请求体,确保服务端收到完整的SOAP XML结构。
  2. 修正Memo赋值逻辑:用Memo1.Lines.Assign(SL)替代直接赋值,避免SL释放后Memo1的内存引用失效。

内容的提问来源于stack exchange,提问作者Robert M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 00:35:35