如何通过Indy组件的TIdHTTP向APNS发送推送通知?
问题根因
- 苹果APNs新接口强制要求使用HTTP/2协议,你当前使用的Indy
TIdHTTP组件原生仅支持HTTP/1.1,手动添加的:method/:scheme/:path等HTTP/2伪头在HTTP/1.1协议下完全无效,这是功能失效的核心原因。 - 你的现有代码还存在多个低级错误,进一步导致请求无法正常发送:
SslIOHandlerHTTP.PassThrough := true会直接跳过SSL握手流程,配置的PEM证书完全不会生效Post方法仅传入域名,未拼接完整的设备路径,且手动配置的:path伪头不会被TIdHTTP识别使用- JSON字符串使用了HTML转义符
"而非原生双引号,请求体格式错误 - 所有创建的组件、流对象未手动释放,存在内存泄漏
修复方案
如果你的Delphi版本在10.4及以上,建议直接使用自带的TNetHTTPClient组件,原生支持HTTP/2协议,适配APNs新要求的代码示例如下:
uses System.Net.HttpClient, System.Net.HttpClientComponent, System.SysUtils, System.Classes, System.JSON; procedure TForm5.BtnPushClick(Sender: TObject); var vHTTP: TNetHTTPClient; vRequest: IHTTPRequest; vResponse: IHTTPResponse; vJsonToSend: TStringStream; vCertFileName: string; vDeviceToken: string; begin vCertFileName := 'apns-dist.pem'; vDeviceToken := '111890052839d3ed4f596c94712329e20812464afe30ebd28487c4e65986c6f0'; vHTTP := TNetHTTPClient.Create(nil); vJsonToSend := TStringStream.Create('{ "aps" : { "alert" : "Hello" } }', TEncoding.UTF8); try // 配置SSL证书 vHTTP.SSLOptions.CertFile := vCertFileName; vHTTP.SSLOptions.KeyFile := vCertFileName; vHTTP.SSLOptions.TLSVersions := [TLSVersion.TLSv12]; // 构建请求 vRequest := vHTTP.CreateRequest('POST', 'https://api.push.apple.com/3/device/' + vDeviceToken); vRequest.Header.Set('apns-id', 'eabeae54-14a8-11e5-b60b-1697f925ec7b'); vRequest.Header.Set('apns-push-type', 'alert'); vRequest.Header.Set('apns-expiration', '0'); vRequest.Header.Set('apns-priority', '10'); vRequest.Header.Set('apns-topic', 'com.TS.JACK'); vRequest.ContentType := 'application/json'; vRequest.SourceStream := vJsonToSend; // 发送请求(自动使用HTTP/2协议) vResponse := vRequest.Execute; Memo1.Lines.Add('响应码:' + IntToStr(vResponse.StatusCode)); Memo1.Lines.Add('响应内容:' + vResponse.ContentAsString); except on E: Exception do begin Memo1.Lines.Add('错误:' + E.Message); end; end; vJsonToSend.Free; vHTTP.Free; end;
如果你必须继续使用Indy组件,需要引入第三方的Indy HTTP/2扩展实现,或者直接使用TIdTCPClient手动封装HTTP/2帧、ALPN协商逻辑,开发成本较高,不推荐。
内容的提问来源于stack exchange,提问作者Johny
相关产品推荐
相关产品推荐

