You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

RAD Studio 11编译Android跨平台SOAP客户端时,如何禁用请求中的BOM(基于WSDL导入器生成代码)

解决RAD Studio 11 Delphi Android平台THTTPRIO发送SOAP请求带BOM的问题

我之前处理过类似的跨平台SOAP客户端问题,结合RAD Studio 11中Delphi SOAP组件的特性,针对你遇到的Android平台请求带UTF-8 BOM导致服务器解析失败的问题,给你几个可行的解决方案:

问题根源

Win32/Win64平台下THTTPRIO生成的SOAP请求默认不会添加UTF-8 BOM,但Android平台的XML流处理实现有差异,会自动在UTF-8编码的XML开头插入BOM(0xEF,0xBB,0xBF),而你的OpenEdge WEB服务不支持带BOM的XML解析,因此触发了Content is not allowed in prolog的SAX解析错误。

解决方案

方法1:通过OnBeforeExecute事件移除BOM

最简单的方式是在SOAP请求发送前,拦截并修改请求流,去掉开头的BOM字节。你可以给THTTPRIO绑定OnBeforeExecute事件,然后在事件处理中清理流:

首先添加一个移除BOM的工具函数:

procedure RemoveUTF8BOM(AStream: TStream);
var
  BOMBytes: array[0..2] of Byte;
  ReadBytes: Integer;
begin
  AStream.Position := 0;
  ReadBytes := AStream.Read(BOMBytes, SizeOf(BOMBytes));
  
  // 检查开头是否是UTF-8 BOM
  if (ReadBytes = 3) and 
     (BOMBytes[0] = $EF) and (BOMBytes[1] = $BB) and (BOMBytes[2] = $BF) then
  begin
    // 移除BOM:将流中剩余内容前移覆盖BOM位置
    AStream.Size := AStream.Size - 3;
    AStream.Position := 3;
    AStream.CopyFrom(AStream, AStream.Size - 3);
    AStream.Position := 0;
  end
  else
    AStream.Position := 0;
end;

然后在你的GetLBLObj函数中,给RIO绑定事件处理:

// 在创建RIO后添加事件绑定
RIO.OnBeforeExecute := procedure(const MethodName: string; SOAPRequest: TStream)
  begin
    RemoveUTF8BOM(SOAPRequest);
  end;

方法2:修改SOAPXMLDoc的编码设置

THTTPRIO内部使用SOAPXMLDoc生成XML内容,我们可以直接修改这个组件的属性,强制它生成不带BOM的UTF-8 XML:

GetLBLObj函数中,添加以下代码(放在RIO创建后):

if Assigned(RIO.SOAPXMLDoc) then
begin
  // 设置XML编码为UTF-8
  RIO.SOAPXMLDoc.Encoding := 'UTF-8';
  // 禁用BOM写入(仅当SOAPXMLDoc是TXMLDocument实例时生效)
  if RIO.SOAPXMLDoc is TXMLDocument then
    TXMLDocument(RIO.SOAPXMLDoc).WriteBOM := False;
  // 确保内容类型头正确
  RIO.HTTPWebNode.ContentType := 'text/xml; charset=utf-8';
end;

方法3:替换THTTPRIO的输出流类型

如果上面的方法都不生效,你可以自定义TStringStream来控制BOM的写入,替换RIO默认的流:

GetLBLObj函数中,修改RIO的OnBeforeExecute事件,将原流替换为不带BOM的UTF-8流:

RIO.OnBeforeExecute := procedure(const MethodName: string; SOAPRequest: TStream)
var
  TempStream: TStringStream;
begin
  if SOAPRequest is TStringStream then
  begin
    // 用不带BOM的UTF-8编码重新创建流
    TempStream := TStringStream.Create(TStringStream(SOAPRequest).DataString, TEncoding.UTF8);
    try
      TempStream.WriteBOM := False;
      // 覆盖原流内容
      SOAPRequest.Position := 0;
      SOAPRequest.Size := 0;
      TempStream.Position := 0;
      SOAPRequest.CopyFrom(TempStream, TempStream.Size);
    finally
      TempStream.Free;
    end;
  end;
end;

验证建议

修改完成后,再次用TCPMon拦截Android应用的SOAP请求,确认请求开头不再有3字节的BOM,直接以<?xml version="1.0"?>开头,此时OpenEdge服务器应该就能正常解析请求了。


内容的提问来源于stack exchange,提问作者Dencho Karaivanov

火山引擎 最新活动