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;
关键修正说明
- 替换请求方法:把
FormPost改为Post,直接传递SL.Text作为请求体,确保服务端收到完整的SOAP XML结构。 - 修正Memo赋值逻辑:用
Memo1.Lines.Assign(SL)替代直接赋值,避免SL释放后Memo1的内存引用失效。
内容的提问来源于stack exchange,提问作者Robert M
相关产品推荐
相关产品推荐

