ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Envoy Mobile HTTP 流式 API 实战:RequestHeaders、StreamPrototype 与 Stream 全解析

Envoy Mobile HTTP 流式 API 实战:RequestHeaders、StreamPrototype 与 Stream 全解析 Envoy Mobile HTTP 流式 API 实战RequestHeaders、StreamPrototype 与 Stream 全解析【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy在 Envoy Mobile 中HTTP 流Stream是一等公民无论是下载大文件、接收服务器推送的数据还是进行双向通信都可以通过统一的流式接口完成传统的 Unary 请求单请求 / 单响应也复用同一套类型只需在写完请求后主动关闭流即可。本篇基于 mobile/docs/root/api/http.rst 官方 API 文档结合仓库内 Kotlin / Swift / C 源码与集成测试系统讲解 HTTP 流的创建、配置、发送、关闭与取消全流程读完即可在 AndroidKotlin与 iOSSwift两端写出可运行的 HTTP 流式客户端代码。一、核心概念为什么 Stream 是一等公民Envoy Mobile 的公开 API 有一个明确目标平台间一致性。因此文档按功能分组并在每个小节同时给出 iOSSwift与 AndroidKotlin示例见 mobile/docs/root/api/api.rst。HTTP 请求在 Envoy Mobile 中统一抽象为「流」其基本链路如下通过EngineBuilder构建Engine再调用streamClient()拿到StreamClient详见 starting_envoy.rst用RequestHeadersBuilder构造RequestHeaders由StreamClient.newStreamPrototype()创建StreamPrototype在启动前挂载响应回调调用StreamPrototype.start(...)得到Stream通过它发送 headers / data / trailers或关闭、取消流。该链路的接口定义在源码中非常清晰Kotlin 侧StreamClient.kt 定义interface StreamClient { fun newStreamPrototype(): StreamPrototype }Swift 侧StreamClient.swift 定义等价的protocol StreamClient。也就是说StreamClient本身不直接发起请求它只负责孵化「流原型」这与 Envoy 内核中「请求先建模、后执行」的思想一致。二、快速开始启动并交互一个 HTTP 流官方文档给出了可直接运行的 Kotlin / Swift 快速示例核心步骤是构建 StreamClient → 构建 RequestHeaders → 创建原型 → 注册回调 → start → 发送。KotlinAndroid示例val streamClient AndroidStreamClientBuilder(application).build() val headers RequestHeadersBuilder(method RequestMethod.POST, scheme https, authority api.envoyproxy.io, path /foo) .build() val stream streamClient .newStreamPrototype() .setOnResponseHeaders { headers, endStream - Log.d(MainActivity, [${headers.httpStatus}] Headers received: $headers, end stream: $endStream) } .setOnResponseData { data, endStream - Log.d(MainActivity, Received data, end stream: $endStream) } .setOnResponseTrailers { trailers - Log.d(MainActivity, Trailers received: $trailers) } .setOnError { ... } .setOnCancel { ... } .start(Executors.newSingleThreadExecutor()) .sendHeaders(...) .sendData(...) // ... stream.close(...)SwiftiOS示例let headers RequestHeadersBuilder(method: .post, scheme: https, authority: api.envoyproxy.io, path: /foo) .build() let streamClient try StreamClientBuilder().build() let stream streamClient .newStreamPrototype() .setOnResponseHeaders { headers, endStream in print([\(headers.httpStatus)] Headers received: \(headers), end stream: \(endStream)) } .setOnResponseData { data, endStream in print(Received data, end stream: \(endStream)) } .setOnResponseTrailers { trailers in print(Trailers received: \(trailers)) } .setOnError { ... } .setOnCancel { ... } .start(queue: .main) .sendHeaders() .sendData(...) // ... stream.close(...)注意两端的两个差异点回调线程Kotlin 侧通过start(executor)指定回调执行的ExecutorSwift 侧通过start(queue:)指定DispatchQueue默认是.main。源码 StreamPrototype.kt 中start(executor: Executor? null)允许为空此时回调直接投递到引擎线程。httpStatus响应头对象ResponseHeaders提供了httpStatus属性可直接读取 HTTP 状态码用于快速判断请求结果。三、RequestHeaders 与 RequestHeadersBuilder构造请求头创建流的入口是初始化一个RequestHeaders实例途径是RequestHeadersBuilder然后把它交给之前创建的StreamClient。构造器需要四个参数method请求方法、schemeURL scheme如https、authorityURL 权威部分如api.envoyproxy.io、pathURL 路径如/foo。Kotlinval headers RequestHeadersBuilder(RequestMethod.POST, https, api.envoyproxy.io, /foo) .addRetryPolicy(RetryPolicy(...)) .addUpstreamHttpProtocol(UpstreamRequestProtocol.HTTP2) .add(x-custom-header, foobar) // ... .build()Swiftlet headers RequestHeadersBuilder(method: .post, scheme: https, authority: api.envoyproxy.io, path: /foo) .addRetryPolicy(RetryPolicy(...)) .addUpstreamHttpProtocol(.http2) .add(name: x-custom-header, value: foobar) // ... .build()从源码看RequestHeadersBuilder的构造器RequestHeadersBuilder.kt、RequestHeadersBuilder.swift会将四个参数映射为 HTTP/2 伪头字段存入内部的 headers 容器参数映射头字段示例值authority:authorityapi.envoyproxy.iomethod:methodPOSTpath:path/fooscheme:schemehttpsscheme参数带默认值https因此大多数场景可以省略。Kotlin 侧RequestMethod枚举RequestMethod.kt完整支持DELETE、GET、HEAD、OPTIONS、PATCH、POST、PUT、TRACE八种方法。Builder 还提供通用的头操作链式方法add(name, value)追加单值、set(name, list)覆盖多值、remove(name)删除以及 Kotlin 端特有的addSocketTag(uid, tag)——通过x-envoy-mobile-socket-tag内部头把流量统计的 UID 与 tag 打到 socket 上Android 数据用量统计场景。addUpstreamHttpProtocol(...)则用于指定上游使用的 HTTP 协议版本如 HTTP/2最终作用于请求发送时的协议协商。四、StreamPrototype启动前配置流StreamPrototype表示「尚未启动的流」由StreamClient创建用于在start()之前把响应回调绑定到流上。它的核心价值是把「请求如何被响应」这件事在流启动前一次性声明好。Kotlinval prototype streamClient .newStreamPrototype() .setOnResponseHeaders { headers, endStream - Log.d(MainActivity, [${headers.httpStatus}] Headers received: $headers, end stream: $endStream) } .setOnResponseData { data, endStream - Log.d(MainActivity, Received data, end stream: $endStream) } .setOnResponseTrailers { trailers - Log.d(MainActivity, Trailers received: $trailers) } .setOnError { ... } .setOnCancel { ... }Swiftlet prototype streamClient .newStreamPrototype() .setOnResponseHeaders { headers, endStream in print([\(headers.httpStatus)] Headers received: \(headers), end stream: \(endStream)) } .setOnResponseData { data, endStream in print(Received data, end stream: \(endStream)) } .setOnResponseTrailers { trailers in print(Trailers received: \(trailers)) } .setOnError { ... } .setOnCancel { ... }对照源码 StreamPrototype.ktSwift 见 StreamPrototype.swift原型上可配置的完整回调集如下setOnResponseHeaders(headers, endStream, streamIntel)收到响应头时触发若endStream true表示这是仅头响应headers-only流即将完成setOnResponseData(data, endStream, streamIntel)收到响应体数据帧时触发endStream true表示最后一帧setOnResponseTrailers(trailers, streamIntel)收到响应尾随头trailers时触发setOnError(error, finalStreamIntel)内部 Envoy 异常时触发流就此结束setOnCancel(finalStreamIntel)流被取消时触发setOnComplete(finalStreamIntel)流正常完成时触发setOnSendWindowAvailable(streamIntel)显式流控模式下发送窗口恢复可用时触发。其中streamIntel/finalStreamIntel是流信息对象携带请求 / 响应各阶段的可观测数据如尝试次数、耗时等。除文档列出的五个回调外原型还支持两个重要配置setExplicitFlowControl(enabled)开启显式流控。开启后调用方需提供缓冲区接收响应体若缓冲区小于可用数据回调会暂停底层网络协议可能向服务器发出停止发送的信号直到有更多空间。好处是限制响应内存占用代价是吞吐量可能下降。Kotlin 端setUseByteBufferPosition(enabled)决定发送ByteBuffer时数据长度取position()还是capacity()见下文 Stream 一节。五、RetryPolicy定制请求重试规则RetryPolicy用于定制出站请求的重试规则通过RequestHeadersBuilder.addRetryPolicy(...)挂到请求上在请求头发送时生效。其核心语义与 Envoy 的重试机制一致自动重试、重试语义、指数退避等均由 Envoy 路由层实现。从源码 RetryPolicy.kt 可以看到它的完整参数参数含义默认值maxRetryCount请求允许的最大重试次数必填retryOn触发重试的规则列表RetryRule枚举必填retryStatusCodes额外的、应当重试的 HTTP 状态码列表空列表perRetryTimeoutMS单次重试的超时毫秒为正数时不得超过totalUpstreamTimeoutMSnulltotalUpstreamTimeoutMS包含所有重试的总超时毫秒覆盖「下游请求处理完成」到「上游响应完全处理完成」的整个区间为null或0表示禁用15000构造器带参数校验若perRetryTimeoutMS为正数且大于totalUpstreamTimeoutMS且后者非 0会直接抛出IllegalArgumentException防止配置出「单次重试比总超时还长」的矛盾策略。RetryRule枚举支持的规则与 Envoy 的x-envoy-retry-on头一一对应STATUS_5XX5xx响应为 5xx 状态码时重试GATEWAY_ERRORgateway-error网关类错误CONNECT_FAILUREconnect-failure连接失败REFUSED_STREAMrefused-stream流被拒绝HTTP/2RETRIABLE_4XXretriable-4xx可重试的 4xx 错误RETRIABLE_HEADERSretriable-headers响应头本身可重试RESETreset连接被重置。实现上RetryPolicy通过outboundHeaders()把这些规则翻译成x-envoy-max-retries、x-envoy-retry-on、x-envoy-retriable-status-codes、x-envoy-upstream-rq-per-try-timeout-ms、x-envoy-upstream-rq-timeout-ms等 Envoy 标准头注入请求反向地RetryPolicy.from(headers)可以从已有RequestHeaders中还原策略对象x-envoy-retry-on的多值会被逗号拆分后逐一映射回枚举。六、Stream启动、发送、关闭与取消流通过StreamPrototype.start()启动返回一个Stream对象发送方用它与网络进行交互。Kotlinval streamClient AndroidStreamClientBuilder() // ... .build() val requestHeaders RequestHeadersBuilder() // ... .build() val prototype streamClient .newStreamPrototype() // ... val stream prototype .start(Executors.newSingleThreadExecutor()) .sendHeaders(...) .sendData(...) // ... stream.close(...)Swiftlet streamClient StreamClientBuilder() // ... .build() let requestHeaders RequestHeadersBuilder() // ... .build() let prototype streamClient .newStreamPrototype() // ... let stream prototype .start(queue: .main) .sendHeaders(...) .sendData(...) // ... stream.close(...)对照 Stream.ktStream提供以下操作除特别说明外均返回自身支持链式调用sendHeaders(headers, endStream, idempotent false)发送请求头。endStream为true表示 headers-only 请求idempotent表示请求是否幂等——置为true时Envoy Mobile 会在 HTTP/3 握手后失败的情况下自动重试默认false。文档的快速示例中 Kotlin 侧调用sendHeaders(...)为单参形式即等价于endStream false的普通发送。sendData(data)发送请求体ByteBuffer/Data。长度默认取capacity若原型开启了setUseByteBufferPosition(true)则取position传入的缓冲区不会被修改但流关闭前对缓冲区的任何改动都可能导致不可预期的结果。readData(byteCount)显式流控模式下主动读取响应数据byteCount是下一次 data 回调可携带的最大字节数调用后立即返回。close(trailers)/close(data)分别用尾随头或最后一个数据帧关闭流即结束请求方向。close(data)等价于发送endStream true的数据帧。cancel()取消整个流。仓库中的 C 集成测试完整覆盖了这些操作如 send_headers_test.cc、send_data_test.cc、send_trailers_test.cc 验证请求方向的发送receive_headers_test.cc、receive_data_test.cc、receive_trailers_test.cc 验证响应方向的回调可作为「每个 API 如何被底层引擎消费」的实现参考。七、Unary 请求把流当一次往返用如前所述Unary 请求复用流的全部类型唯一区别是写完 headers / data / trailers 后立即关闭流让请求方向结束随后在响应回调中接收完整响应。Kotlinval streamClient AndroidStreamClientBuilder() // ... .build() val requestHeaders RequestHeadersBuilder() // ... .build() val stream streamClient .newStreamPrototype() .start(Executors.newSingleThreadExecutor()) // Headers-only stream.sendHeaders(requestHeaders, true) // Close with data stream.close(ByteBuffer(...)) // Close with trailers stream.close(RequestTrailersBuilder().build()) // Cancel the stream stream.cancel()Swiftlet streamClient StreamClientBuilder() // ... .build() let requestHeaders RequestHeadersBuilder() // ... .build() let stream streamClient .newStreamPrototype() .start(queue: .main) // Headers-only stream.sendHeaders(requestHeaders, endStream: true) // Close with data stream.close(Data(...)) // Close with trailers stream.close(RequestTrailersBuilder().build()) // Cancel the stream stream.cancel()四种「收尾」方式的适用场景Headers-onlysendHeaders(headers, endStream true)请求只有头没有体如典型的GET发出即代表请求方向结束Close with data请求体较大时把最后一个数据块连同「结束」标记一起发送Close with trailers请求需要携带尾随头如分块元数据时使用Cancel主动放弃请求例如用户中途退出页面此时不会再产生任何响应回调。RequestTrailersBuilder与RequestHeadersBuilder结构对称同样支持add/set/remove链式操作后build()见 RequestTrailersBuilder.kt。八、StreamClient 从哪来与 Engine 的关系本文大量使用streamClient它的获取方式在 starting_envoy.rst 中有完整说明先通过EngineBuilderAndroid 为AndroidEngineBuilder配置并构建Engine再调用engine.streamClient()取得可复用的StreamClient之后所有网络请求都通过它发起val streamClient AndroidEngineBuilder(getApplication()) .setLogLevel(LogLevel.WARN) // ... .build() .streamClient()let streamClient try EngineBuilder() .setLogLevel(.warn) // ... .build() .streamClient()EngineBuilder还支持连接超时、DNS 刷新策略、HTTP/3QUIC、Gzip/Brotli 解压、xDS 动态配置、日志与事件追踪等一系列引擎级配置若默认配置不够用还可以直接传入自定义 Envoy YAML 配置AndroidEngineBuilder(context, Yaml(yamlString))/EngineBuilder(yaml:)但官方特别提醒自定义 YAML 要到运行时才会被求值且并非所有 Envoy 核心配置项都被 Envoy Mobile 支持使用不当可能导致运行时崩溃。九、小结与最佳实践先建原型再启流所有响应回调必须在start()之前通过StreamPrototype声明完毕流一旦启动便不可再追加回调Unary 与流式用同一套 APIUnary 只是「写完即关」流式则保持Stream打开并持续sendData/ 在setOnResponseData中消费数据重试交给 Envoy通过RetryPolicy声明式配置重试规则由 Envoy 在请求头发送时统一注入并执行业务层无需自建重试逻辑留意线程模型回调线程由start时的ExecutorKotlin或DispatchQueueSwift决定UI 更新类回调建议传入主线程队列大响应考虑显式流控setExplicitFlowControl(true)readData(byteCount)可以在内存敏感场景下限制单次回调携带的数据量。以上内容与接口签名均可对照仓库源码验证Swift 侧实现见 StreamClient.swift 与 StreamPrototype.swiftKotlin 侧见 StreamClient.kt、StreamPrototype.kt 与 Stream.kt端到端行为可由 mobile/test/cc/integration 下的集成测试进一步佐证。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表