Jersey发送带请求体GET请求报Entity must be null异常如何解决
问题描述
调用支付服务商外部API时,选用Jersey与javax.ws.rs发起请求,利用框架内置能力实现Digest认证。但发起携带payload载荷的GET请求时,框架返回如下异常:
IllegalStateException. Entity must be null for http method GET
对应业务实现代码如下:
CashTransactionResponse responseData = null; // 对接intouch服务端 String requestUrl = rootUrlTouchPay + agency.getAgencyCode() + "/" + IntouchMethodApis.TRANSACTION + "?loginAgent=" + agency.getLogin() + "&passwordAgent=" + agency.getPassword(); ClientConfig clientConfig = new ClientConfig(); // 开启Digest认证 HttpAuthenticationFeature feature = HttpAuthenticationFeature.digest(BASIC_LOGIN, BASIC_PWD); clientConfig.register(feature); clientConfig.register(JacksonFeature.class); // 创建REST客户端 Client client = ClientBuilder.newClient(clientConfig); clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true); // 构造请求地址 WebTarget webTarget = client.target(requestUrl); Invocation.Builder invocationBuilder = webTarget.request(javax.ws.rs.core.MediaType.APPLICATION_JSON); logger.info("Initialisation of cashout service successful for cash"); // 序列化请求参数 Gson gson = new Gson(); String transactionString = gson.toJson(cashRequest); Response response = null; // 发起请求 if (cashRequest.getServiceCode().contains(TelecomEnum.WAVE.name().toUpperCase())) { response = invocationBuilder.method("GET", Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON)); } else { response = invocationBuilder.put(Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON)); }
需要实现携带请求体的GET请求发送能力。
解决方案
根因说明
HTTP/1.1规范中GET方法的语义为资源检索,未对GET请求携带请求体的行为做统一标准化约定,Jersey作为合规HTTP客户端实现,默认会拦截携带实体的GET请求,直接抛出上述异常。
另外现有代码存在配置顺序错误:SUPPRESS_HTTP_COMPLIANCE_VALIDATION(关闭HTTP合规校验)属性的设置在ClientBuilder.newClient()调用之后,Client实例创建时已经完成配置加载,该校验关闭参数实际未生效。
修复操作
- 调整配置加载顺序,将合规校验关闭的配置移到Client实例创建之前:
ClientConfig clientConfig = new ClientConfig(); // 注册Digest认证、JSON序列化组件 HttpAuthenticationFeature feature = HttpAuthenticationFeature.digest(BASIC_LOGIN, BASIC_PWD); clientConfig.register(feature); clientConfig.register(JacksonFeature.class); // 提前关闭HTTP规范校验,再实例化Client clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true); Client client = ClientBuilder.newClient(clientConfig);
- 如果调整顺序后依然抛出相同异常,说明当前使用的Jersey版本在请求构造逻辑中硬编码了GET方法禁止携带实体的判断,可替换为Apache HttpClient连接器绕过原生校验:
- 引入和当前Jersey版本匹配的
jersey-apache-connector依赖 - 给ClientConfig添加连接器配置:
clientConfig.connectorProvider(new ApacheConnectorProvider()); - 引入和当前Jersey版本匹配的
- 客户端侧绕过校验后,需要额外确认目标支付服务商的网关、负载均衡、WAF、服务端程序不会主动丢弃GET请求的请求体:大量HTTP中间件默认会忽略GET请求的body内容,很容易出现参数丢失的问题。如果联调时发现服务端收不到请求体参数,优先和服务商确认接口文档的请求方法是否标注错误,这类要求GET带请求体的场景,多数是文档笔误,实际要求使用POST/PUT方法。
内容的提问来源于stack exchange,提问作者Teddy Kossoko
相关产品推荐
相关产品推荐

