You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

REST Web服务出现500错误时,如何获取PUT请求的原始JSON对象?

当然有办法获取到原始的JSON请求体!针对你用的JAX-RS(从配置里的jaxrs:server能看出来是Apache CXF场景),我给你几个实用的解决方案:

方案1:提前用请求过滤器缓存请求体

JAX-RS的请求体默认只能读取一次,所以我们得在请求到达业务接口前就把请求体缓存起来,这样哪怕后续抛出500错误,也能拿到原始内容。

  1. 实现ContainerRequestFilter过滤器,读取并缓存请求体:
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

@Provider
public class RequestBodyCachingFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // 只针对PUT类型的JSON请求处理
        if ("PUT".equalsIgnoreCase(requestContext.getMethod()) 
            && requestContext.getMediaType().isCompatible(MediaType.APPLICATION_JSON_TYPE)) {
            
            InputStream originalStream = requestContext.getEntityStream();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = originalStream.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesRead);
            }
            byte[] requestBodyBytes = baos.toByteArray();
            
            // 把缓存的字节流放回上下文,保证后续业务代码能正常读取
            requestContext.setEntityStream(new ByteArrayInputStream(requestBodyBytes));
            
            // 将原始JSON字符串存入请求属性,后续异常处理时可以直接获取
            String charset = requestContext.getMediaType().getParameters().getOrDefault("charset", "UTF-8");
            String rawJson = new String(requestBodyBytes, charset);
            requestContext.setProperty("RAW_REQUEST_JSON", rawJson);
        }
    }
}
  1. 在application-context.xml里注册这个过滤器:
<jaxrs:server id="VehicleConnectedMileageREST" address="/your-service-path">
    <!-- 你的其他接口配置 -->
    <jaxrs:providers>
        <bean class="com.your.package.RequestBodyCachingFilter"/>
    </jaxrs:providers>
</jaxrs:server>

方案2:用ExceptionMapper捕获500异常时提取缓存的JSON

接下来实现一个异常处理器,捕获服务器内部错误(500),并取出之前缓存的原始JSON:

import javax.ws.rs.core.Context;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {

    @Context
    private Request request;
    
    @Override
    public Response toResponse(Throwable exception) {
        // 从请求属性中取出缓存的原始JSON
        String rawJson = (String) request.getProperty("RAW_REQUEST_JSON");
        
        // 这里可以做日志记录、错误分析等操作
        if (rawJson != null) {
            System.err.println("触发500错误的PUT请求原始JSON:\n" + rawJson);
        }
        
        // 返回标准的500响应,也可以自定义响应内容
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                       .entity("服务器内部处理错误")
                       .build();
    }
}

别忘了把这个异常处理器也注册到jaxrs:providers里:

<jaxrs:providers>
    <bean class="com.your.package.RequestBodyCachingFilter"/>
    <bean class="com.your.package.GenericExceptionMapper"/>
</jaxrs:providers>

方案3:在业务方法内直接捕获异常处理

如果只需要在updateConnectedVehiclemileage这个特定方法里处理,也可以结合上下文直接在方法内获取缓存的JSON:

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Context;

public class VehicleConnectedMileageApiImpl implements VehicleConnectedMileageApi {

    @Context
    private ContainerRequestContext requestContext;

    @Override
    public Response updateConnectedVehiclemileage(Vehicle vehicle) throws NotFoundException {
        String rawJson = (String) requestContext.getProperty("RAW_REQUEST_JSON");
        try {
            // 执行业务逻辑
            // ...
            return Response.ok().build();
        } catch (Exception e) {
            // 发生错误时处理原始JSON
            if (rawJson != null) {
                System.err.println("当前错误请求的原始JSON:\n" + rawJson);
            }
            throw new RuntimeException("服务器内部处理失败", e);
        }
    }
}

小提醒

  • 如果是其他JAX-RS实现(比如Jersey),核心逻辑完全通用,只是注册过滤器/处理器的方式可能略有不同。
  • 如果请求体特别大,缓存到内存可能有性能问题,这时候可以考虑把内容写入临时文件存储。

内容的提问来源于stack exchange,提问作者abderrahim_05

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:17:50