如何通过Indy TIdHTTP获取连续HTTP实时交易数据流并在下载中读取
你之前使用返回字符串的TIdHTTP.Post重载无法实时获取数据,是因为Indy默认会等待整个HTTP响应传输完成后才会把完整内容拼接成字符串返回,而你的目标接口返回的是无限持续的推送流,永远不会结束传输,自然拿不到数据。
你不需要额外使用IdIOHandlerStream,现有的IdSSLIOHandlerSocketOpenSSL已经可以满足SSL传输需求,只需要改用带输出流的Post重载,配合TIdHTTP的OnWork事件实时处理收到的数据包即可,具体实现步骤如下:
1. 预先准备
首先在窗体类中声明一个缓冲变量,用来存储收到的不完整行数据,避免拆分JSON时出现断行:
private FRecvBuffer: string; // 存储未处理的不完整行数据
2. 配置组件属性
- 把
TIdHTTP组件的IOHandler属性绑定到IdSSLIOHandlerSocketOpenSSL,正常配置SSL参数即可,不需要额外调整IOHandler相关配置 - 给
TIdHTTP组件绑定OnWork事件,用来处理实时到达的数据包
3. 调整请求代码
不要使用返回字符串的Post重载,改用带输出流参数的重载:
var Lrequest: TStringList; LResponseStream: TMemoryStream; begin Lrequest := TStringList.Create; LResponseStream := TMemoryStream.Create; try Lrequest.Values['__RequestVerificationToken'] := RequestVerificationToken; Lrequest.Values['acct'] := 'demo'; Lrequest.Values['pwd'] := 'demo'; FRecvBuffer := ''; // 每次发起请求前清空缓冲 try // 带输出流的Post重载会持续把收到的响应数据写入LResponseStream Onhttp.Post('https://trading/data', Lrequest, LResponseStream); except on E: Exception do Memo1.Lines.Add(TimeToStr(Time) + ': ' + E.ClassName + ' 错误,信息:' + E.Message); end; finally LResponseStream.Free; Lrequest.Free; end; end;
4. 实现OnWork事件逻辑
每次收到新的数据包时,从流中读取新增内容,按行拆分出完整的JSON对象进行处理:
procedure TForm1.OnhttpWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64); var LNewData: string; LLine: string; LLineEndPos: Integer; LStreamPos: Int64; begin // 只处理接收数据的事件,跳过发送数据的事件 if AWorkMode <> wmRead then Exit; // 先记录流的当前位置,读完后复位,不影响Indy后续写入数据 LStreamPos := Onhttp.Response.ContentStream.Position; try Onhttp.Response.ContentStream.Position := LStreamPos - (AWorkCount - Length(FRecvBuffer)); // 读取本次新增的所有数据 SetLength(LNewData, AWorkCount - Length(FRecvBuffer)); Onhttp.Response.ContentStream.ReadBuffer(PChar(LNewData)^, Length(LNewData)); finally Onhttp.Response.ContentStream.Position := LStreamPos; end; // 把新数据加入缓冲 FRecvBuffer := FRecvBuffer + LNewData; // 逐行拆分完整的JSON while Pos(#10, FRecvBuffer) > 0 do begin LLineEndPos := Pos(#10, FRecvBuffer); LLine := Trim(Copy(FRecvBuffer, 1, LLineEndPos - 1)); Delete(FRecvBuffer, 1, LLineEndPos); // 过滤空行,处理完整的JSON行 if LLine <> '' then begin Memo1.Lines.Add(TimeToStr(Time) + ': 收到数据:' + LLine); // 此处添加你自己的JSON解析逻辑即可 end; end; end;
注意事项
- 由于该请求是无限持续的流,
Post方法会一直阻塞,所以不要把请求逻辑放在主线程执行,要放到独立的工作线程中运行,否则会导致界面卡死。 - 需要停止接收数据时,直接调用
Onhttp.Disconnect即可,会触发断开异常,正常捕获后处理退出逻辑即可。
内容的提问来源于stack exchange,提问作者Int20h
相关产品推荐
相关产品推荐

