Jersey 客户端错误 - 无法解析无效的 Content-Type 标头(需要解决方法)

Posted

技术标签:

【中文标题】Jersey 客户端错误 - 无法解析无效的 Content-Type 标头(需要解决方法)【英文标题】:Jersey Client Error - Unable to Parse Invalid Content-Type Header (need workaround) 【发布时间】:2021-09-03 15:43:30 【问题描述】:

我相信我正在使用 Jersey 客户端 2.29。 在处理请求时,服务器会以Content-Type = application/ 响应(当然这是一个虚假值,它应该是application/json)。 jersey 炸了,因为它无法解析媒体类型的子类型:

java.util.concurrent.CompletionException: org.glassfish.jersey.message.internal.HeaderValueException: Unable to parse "Content-Type" header value: "application/"
    at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
    at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.glassfish.jersey.message.internal.HeaderValueException: Unable to parse "Content-Type" header value: "application/"
    at org.glassfish.jersey.message.internal.InboundMessageContext.exception(InboundMessageContext.java:314)
    at org.glassfish.jersey.message.internal.InboundMessageContext.singleHeader(InboundMessageContext.java:309)
    at org.glassfish.jersey.message.internal.InboundMessageContext.getMediaType(InboundMessageContext.java:422)
    at com.test.web.ext.filter.LoggingFilter.filter(LoggingFilter.java:94)
    at org.glassfish.jersey.client.ClientFilteringStages$ResponseFilterStage.apply(ClientFilteringStages.java:109)
    at org.glassfish.jersey.client.ClientFilteringStages$ResponseFilterStage.apply(ClientFilteringStages.java:97)
    at org.glassfish.jersey.process.internal.Stages.process(Stages.java:147)
    at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:259)
    at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$1(JerseyInvocation.java:743)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:390)
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:741)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:432)
    at org.glassfish.jersey.client.JerseyCompletionStageRxInvoker.lambda$method$1(JerseyCompletionStageRxInvoker.java:46)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
    ... 3 more
Caused by: javax.ws.rs.ProcessingException: java.lang.IllegalArgumentException: Error parsing media type 'application/'
    at org.glassfish.jersey.message.internal.InboundMessageContext$5.apply(InboundMessageContext.java:428)
    at org.glassfish.jersey.message.internal.InboundMessageContext$5.apply(InboundMessageContext.java:422)
    at org.glassfish.jersey.message.internal.InboundMessageContext.singleHeader(InboundMessageContext.java:307)
    ... 18 more
Caused by: java.lang.IllegalArgumentException: Error parsing media type 'application/'
    at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:69)
    at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:37)
    at javax.ws.rs.core.MediaType.valueOf(MediaType.java:196)
    at org.glassfish.jersey.message.internal.InboundMessageContext$5.apply(InboundMessageContext.java:426)
    ... 20 more
Caused by: java.text.ParseException: End of header.
    at org.glassfish.jersey.message.internal.HttpHeaderReaderImpl.getNextCharacter(HttpHeaderReaderImpl.java:155)
    at org.glassfish.jersey.message.internal.HttpHeaderReaderImpl.next(HttpHeaderReaderImpl.java:116)
    at org.glassfish.jersey.message.internal.HttpHeaderReaderImpl.next(HttpHeaderReaderImpl.java:111)
    at org.glassfish.jersey.message.internal.HttpHeaderReader.nextToken(HttpHeaderReader.java:104)
    at org.glassfish.jersey.message.internal.MediaTypeProvider.valueOf(MediaTypeProvider.java:90)
    at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:67)
    ... 23 more

github-MediaTypeProvider 我无法控制此第 3 方服务器,我必须能够处理此请求。 反正有这个吗? 一些属性、设置、注册自定义媒体类型提供程序,什么?

附: 我已经成功地使用ByteBuddy 在运行时重新定义了这个方法,并用一些额外的特殊调味料来处理错误,但这是一个重大的黑客攻击......如果它存在,我希望有更好的选择。

客户端配置

final Client client = ClientBuilder.newBuilder()
  .property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.CHUNKED)
  .property(ClientProperties.FOLLOW_REDIRECTS, false)
  .sslContext(tls)
  .hostnameVerifier(new NoOpHostnameVerifier())
  .register(new CookiePersistFilter(NARRATIVE)) // @Priority(HEADER_DECORATOR)
  .register(new LoggingFilter(NARRATIVE))       // @Priority(USER)
  .register(MyFilter.class)                     // @Priority(50000)
  .register(JsonReader.class)
  .register(JsonWriter.class)
  .register(htmlReader.class)
  .register(MultiPartFeature.class)
  .build();

过滤器按以下顺序执行:

    我的过滤器 日志过滤器 CookiePersistFilter

【问题讨论】:

由于在调用readEntity() 之前不会出现此错误,我认为您可以在调用readEntity() 之前手动设置响应标头。喜欢response.getHeaders().putSingle("Content-Type", "application/json") 嗨@PaulSamsotha,谢谢你的想法。我已经更新了在过滤器中显示这种情况的堆栈跟踪。因此,我认为我需要在读取实体之前处理此问题,否则它会通过任何其他过滤器以确保安全。我可以使用响应过滤器吗?如果是这样,我如何优先考虑它?我尝试使用 @Rank(1) 进行注释,但它似乎对排序没有任何影响(它首先调用我的另一个过滤器,排名 Priorities.USER 爆炸了)。 使用优先级的正确方法是使用@Priority 或者当您调用register() -- 使用让您指定数字优先级的重载。 我的错@PaulSamsotha,我混淆了排名和优先级。所以我尝试了优先级,它奏效了。但是,订购不是我所期望的。对于我的球衣客户,当优先级文档说明相反时,它似乎按降序排序(最高数字,最高优先级)。这是预期的吗? 为了以防万一,我在客户端配置中添加了过滤器排序。 【参考方案1】:

正如Paul Samsotha 指出的那样,我可以使用ClientResponseFilter 使用高优先级来解决此问题。这是一种可以做到的方法。

import javax.annotation.Priority;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;

import com.selinc.winchester.common.narrative.INarrative;
import com.selinc.winchester.sentinel.Sentinel;
import com.selinc.winchester.wrestler.ResponsePriorities;

@Provider
@Priority(25000) // Note the priority ordering is reverse of ClientRequestFilter
public final class ResponseHeaderWorkaroundFilter implements ClientResponseFilter

  @Override
  public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext)
  
    try
    
      // Attempt to read the Content-Type header.
      responseContext.getMediaType();
    
    catch (Throwable error)
    
      // On error, set the Content-Type header to some default value.
      responseContext.getHeaders()
        .putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
    
  

【讨论】:

以上是关于Jersey 客户端错误 - 无法解析无效的 Content-Type 标头(需要解决方法)的主要内容,如果未能解决你的问题,请参考以下文章

错误:无法解析提供的 SSML。提供的文本无效 SSML

MAVEN BUILD FAILURE - 无法解析项目 XYZ 的依赖关系

由于解析错误,项目“project”已损坏,无法打开。检查项目文件中的无效编辑...控制冲突

Nuget包安装错误 - 无效的URI:无法解析权限/主机

无法模拟 Glassfish Jersey 客户端响应对象

BigQuery - Apache Avro 库无法解析标头并出现以下错误:数据文件无效。魔法不匹配