Android 10+下TWebBrowser中XMLHttpRequest POST数据无法发送
使用Delphi 11.3或10.4.1开发,通过TWebBrowser组件(变量名AWB)执行JavaScript发送POST请求,代码如下:
AWB.EvaluateJavaScript( // 'alert( "var3=pmp ap pn q m" );' + #13 + #10 + // 该代码始终正常工作 '{ let xhr = new XMLHttpRequest();' + #13 + #10 + 'xhr.open("POST", "http://127.0.0.1:50001", false);' + #13 + #10 + 'xhr.send("var3=pmp ap pn q m");' + #13 + #10 + ' }');
其中JS的alert功能正常。
服务器端使用TIdHTTPServer接收请求,DFM配置如下:
object IdHTTPServer1: TIdHTTPServer Bindings = < item IP = '127.0.0.1' Port = 50001 end> DefaultPort = 50001 TerminateWaitTime = 1000 AutoStartSession = True ParseParams = False OnCommandGet = IdHTTPServer1CommandGet end
通过IdHTTP1直接POST到本地服务器可正常接收:
var JSon : TStringStream; Json := TStringStream.Create('Hee ll p', TEncoding.UTF8); IdHTTP1.Post('http://127.0.0.1:50001', Json);
核心问题:XMLHttpRequest的POST请求在Android 8.1(MIUI 9.6)上正常,但在Android 10(MIUI 12)和Android 12(MIUI 14)上,服务器端的ARequestInfo.PostStream为空,无法获取POST数据。项目基于Embarcadero官方示例:C:\Users\Public\Documents\Embarcadero\Studio\22.0\Samples\Object Pascal\Mobile Snippets\WebBrowser
服务器端处理代码:
procedure TWebBrowserForm.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); var Stream : TStream; begin AResponseInfo.ResponseNo:= 200; AResponseInfo.ContentText:= 'OKOK'; if ARequestInfo.Command = 'POST' then begin Stream := ARequestInfo.PostStream; // Android 10+下此处为nil if assigned(Stream) then begin FAnswer_Content := ReadStringFromStream(Stream, -1, IndyTextEncoding_UTF8); end end; end;
1. 补充请求头信息
Android 10+的WebView(TWebBrowser底层基于WebView)对XHR请求的规范要求更严格,未指定Content-Type头时,可能导致请求体被丢弃。修改JavaScript代码,添加Content-Type:
{ let xhr = new XMLHttpRequest(); xhr.open("POST", "http://127.0.0.1:50001", false); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send("var3=pmp ap pn q m"); }
对应Delphi代码转义后:
AWB.EvaluateJavaScript( '{ let xhr = new XMLHttpRequest();' + #13 + #10 + 'xhr.open("POST", "http://127.0.0.1:50001", false);' + #13 + #10 + 'xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");' + #13 + #10 + 'xhr.send("var3=pmp ap pn q m");' + #13 + #10 + ' }');
2. 调整服务器端参数解析配置
当前服务器ParseParams = False,虽然直接读取PostStream理论可行,但Android 10+的请求可能触发Indy的参数解析逻辑异常。建议将ParseParams设为True,同时增加FormParams读取作为备选:
procedure TWebBrowserForm.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); var Stream : TStream; begin AResponseInfo.ResponseNo:= 200; AResponseInfo.ContentText:= 'OKOK'; if ARequestInfo.Command = 'POST' then begin // 优先读取FormParams if ARequestInfo.FormParams.Count > 0 then begin FAnswer_Content := ARequestInfo.FormParams.Text; end else if Assigned(ARequestInfo.PostStream) then begin Stream := ARequestInfo.PostStream; FAnswer_Content := ReadStringFromStream(Stream, -1, IndyTextEncoding_UTF8); end; end; end;
3. 确认应用权限配置
Android 10+对本地网络访问有更严格的限制,确保应用已申请以下权限:
INTERNET:允许网络访问ACCESS_NETWORK_STATE:获取网络状态
在Delphi项目中,可通过项目选项 -> Permissions标签直接勾选对应权限,无需手动修改AndroidManifest.xml。
内容的提问来源于stack exchange,提问作者Станислав 000

