如何修复Scala HTTP请求addHeader不生效 跨请求复制请求头问题
核心问题定位
Akka HTTP 框架中HttpRequest属于不可变值类,所有修改类方法(包括addHeader)不会直接修改当前实例,而是返回携带修改结果的全新对象。
原代码循环调用request.addHeader(h)时,没有将方法返回的新实例重新赋值,原请求对象的headers始终保留初始化时传入的空列表Nil,因此后续打印日志时看不到任何已添加的请求头。
正确实现方案
跨请求复制请求头时,需要主动过滤和单次请求强绑定、无法跨请求透传的头部,避免触发HTTP协议解析错误,需要过滤的头部包括:Host、Content-Length、Connection、Transfer-Encoding、Keep-Alive。
实现代码示例
private def apiPostRequest(path: String, host: HostStoreInfo, byteString: ByteString, prevRequest: HttpRequest): Future[HttpResponse] = { // 定义不可透传的头部列表 val excludedHeaders = Set("Host", "Content-Length", "Connection", "Transfer-Encoding", "Keep-Alive") // 从旧请求中筛选可复制的头部 val copiedHeaders = Option(prevRequest) .map(_.headers.filterNot(h => excludedHeaders.contains(h.name))) .getOrElse(Nil) // 初始化新请求时直接传入筛选后的请求头 val request = HttpRequest( method = HttpMethods.POST, uri = s"http://${host.host}:${host.port}$path", headers = copiedHeaders, entity = HttpEntity.apply(byteString) ) logger.info("Previous request " + prevRequest) logger.info("Here are the headers " + request.headers) Http().singleRequest(request) }
如果需要基于旧请求的其他属性做调整,也可以借助copy方法构造新实例:
private def apiPostRequest(path: String, host: HostStoreInfo, byteString: ByteString, prevRequest: HttpRequest): Future[HttpResponse] = { val excludedHeaders = Set("Host", "Content-Length", "Connection", "Transfer-Encoding", "Keep-Alive") if (prevRequest == null) { val request = HttpRequest( method = HttpMethods.POST, uri = s"http://${host.host}:${host.port}$path", entity = HttpEntity.apply(byteString) ) return Http().singleRequest(request) } // 筛选合法可复制的头部 val validHeaders = prevRequest.headers.filterNot(h => excludedHeaders.contains(h.name)) // 复制旧请求对象,覆盖需要调整的属性 val newRequest = prevRequest.copy( method = HttpMethods.POST, uri = s"http://${host.host}:${host.port}$path", headers = validHeaders, entity = HttpEntity.apply(byteString) ) Http().singleRequest(newRequest) }
注意事项
- 不建议全量复制所有请求头,否则会因新旧Host、请求体元数据冲突,被Akka HTTP客户端拦截抛出协议异常
- 仅需要透传少量自定义业务头时,使用头部白名单的方式比全量过滤更安全可控
内容的提问来源于stack exchange,提问作者hareendra reddy
相关产品推荐
相关产品推荐

