Springboot / HttpServletResponse 未检索实际的 HTTP 主体

问题描述 投票:0回答:1

我在 Spring boot 项目中面临一个奇怪的问题,其中主体在控制器中不可检索。 这有点具体:我正在使用 bc tls psk 方案与 SIM 卡通信,并且它已经工作了好几年,没有出现任何故障,但是现在当与特定卡/设备交换时,卡发送的有效负载在以下位置不可用我的控制器。

我正在使用 Springboot 2.5.15、Java 8、BC jdk8on 1.78.1。

我进行了 tcpdump 跟踪,我确实看到了有效负载 AF 80 23 11 .. .. 00 00 (SIM 卡是这样说话的,请不要评判它们!)。 所以我无法检索该有效负载即使它存在于两者TCP跟踪和内容长度标头告诉我它在那里。

这是 TCPDUMP 屏幕截图:

Failure case

我的控制器:

public void anyRequest(@RequestHeader(value = CONTENT_TYPE, required = false) String requestContentType,
            @RequestHeader(value = HEADER_X_ADMIN_PROTOCOL) String adminProtocol,
            @RequestHeader(value = HEADER_X_ADMIN_FROM) String adminFrom,
            @RequestHeader(value = HEADER_X_ADMIN_RESUME, required = false, defaultValue = "false") boolean adminResume,
            @RequestHeader(value = HEADER_X_ADMIN_SCRIPT_STATUS, required = false) String adminScriptStatus,
            @RequestBody(required = false) byte[] body, final HttpServletRequest request,
            final HttpServletResponse response) throws InterruptedException, IOException {

在那里我通常会得到这样的身体:

Long contentLength = request.getContentLengthLong();
log.info("Request Content lenght in header: {}", contentLength);
if (body != null) {
    log.info("body content {} ", Hex.encodeHexString(body));
            }

再次强调,它在 99% 的情况下都有效。但是当我使用特定设备时,它不会,body 保持为空。

我什至尝试过其他几种方式来获得它,但没有运气

尝试数字1:

if (body == null && contentLength > 0) {

    log.warn("Body seems null while Content length Header is {} ", contentLength);
    log.info("Trying alternative way to retreive the body {} ", contentLength);
    InputStream is = request.getInputStream();
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    int nRead;
    byte[] data = new byte[16384];
    while ((nRead = is.read(data, 0, data.length)) != -1) {
        buffer.write(data, 0, nRead);
        }
    body = buffer.toByteArray();
}

尝试数字 2:(这实际上是返回一个由零组成的字节数组,但值得尝试)

private byte[] alternateBodybytes(InputStream serveltInputStream, int contentLength) throws IOException {

        byte[] bytes = new byte[contentLength];
        for (int r, offset = 0; (r = serveltInputStream.read(bytes, offset, bytes.length - offset)) > -1;) {
            offset += r;
        }
        
        return bytes;

    }

我现在没有选项了,正在寻找建议,如果你们有的话?

  • 是否有另一种方法可以在 Springboot 框架内堆栈的较低级别获取原始有效负载?
  • 我希望不必更新 Spring / Java,因为这会让我有更多的回归工作要做,但可能需要时间。

你觉得怎么样?有什么建议吗?

注意:下面是一个交易的 TCP 跟踪,我可以从 @RequestBody(required = false) byte[] body 获取正文,对我来说,它看起来完全一样,对吧?

success case

java spring-boot servlets tcpdump
1个回答
0
投票

评论建议我使用 StreamUtils 和/或 ContentCachingRequestWrapper 来确保我的 bodyu 尚未被消耗。我使用了 iun 序列,但仍然没有看到所需的内容。

public void anyRequest(@RequestHeader(value = CONTENT_TYPE, required = false) String requestContentType,
            @RequestHeader(value = HEADER_X_ADMIN_PROTOCOL) String adminProtocol,
            @RequestHeader(value = HEADER_X_ADMIN_FROM) String adminFrom,
            @RequestHeader(value = HEADER_X_ADMIN_RESUME, required = false, defaultValue = "false") boolean adminResume,
            @RequestHeader(value = HEADER_X_ADMIN_SCRIPT_STATUS, required = false) String adminScriptStatus,
            @RequestBody(required = false) byte[] body, final HttpServletRequest request,
            final HttpServletResponse response) throws InterruptedException, IOException {

        
        ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;

[...]

if (body == null && contentLength > 0) {
            
            log.warn("Body seems null while Content length Header is {} ", contentLength);
            log.info("Trying alternative way #1 to retreive the body using requestWrapper");
            
            byte[] requestPayload = requestWrapper.getContentAsByteArray();
            
            if (requestPayload != null && requestPayload.length > 0) {
                log.info("Managed to retreive a body of length {} ", requestPayload.length);
                log.info("alternative body content {} ", Hex.encodeHexString(requestPayload));
                body = requestPayload;
            } else {
                log.warn("Couldnt get the content body using Method 1");
                log.warn("Trying alternative way #2 to retreive the body using alternateBodybytes2");
                
                requestPayload = requestPayload = StreamUtils.copyToByteArray(requestWrapper.getInputStream());
                if (requestPayload != null) {
                    log.info("Managed to retreive a body of length {} ", requestPayload.length);
                    log.trace("alternative 2 body content {} ", Hex.encodeHexString(requestPayload));
                } else {
                    
                    log.error("Couldnt extract body content");
                }
                
            }
            
            body = requestPayload;
            
        }

以下日志的结果相同:

2024-09-30 09:24:56.149  INFO 4165202 --- [https-psk-bc-nio2-9100-exec-25] c.c.RemoteAdministrationServerController : Request Content length in header: 23
2024-09-30 09:24:56.149  WARN 4165202 --- [https-psk-bc-nio2-9100-exec-25] c.c.RemoteAdministrationServerController : Body seems null while Content length Header is 23
2024-09-30 09:24:56.149  INFO 4165202 --- [https-psk-bc-nio2-9100-exec-25] c.c.RemoteAdministrationServerController : Trying alternative way #1 to retreive the body using requestWrapper
2024-09-30 09:24:56.149  WARN 4165202 --- [https-psk-bc-nio2-9100-exec-25] c.c.RemoteAdministrationServerController : Couldnt get the content body using Method 1
2024-09-30 09:24:56.149  WARN 4165202 --- [https-psk-bc-nio2-9100-exec-25] c.c.RemoteAdministrationServerController : Trying alternative way #2 to retreive the body using alternateBodybytes2

@网络列车

这里是TCP层的差异,可能是因为重新组装的数据包?你看到什么奇怪的东西了吗?

交易失败

Failed Transacation

交易成功:

Succesful transaction

© www.soinside.com 2019 - 2024. All rights reserved.