jeecgboot/JeecgBoot · error · IllegalArgumentException

无法获取请求上下文

Error message

无法获取请求上下文

What it means

Thrown by SignatureCheckAspect.doSignatureValidation() when RequestContextHolder.getRequestAttributes() returns null — the current thread has no servlet request context bound to it. This AOP aspect runs as a @Before advice on methods annotated with @SignatureCheck; if the method is somehow invoked outside of an HTTP request thread (where RequestContextHolder has no attributes), this guard fires.

Source

Thrown at jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/aspect/SignatureCheckAspect.java:82

        // update-begin---author:sjlei---date:20260115 for: 查找带有@RequestBody注解的参数,解决签名校验时读取请求体为空的问题
        Object bodyParam = null;
        Object[] args = point.getArgs();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            Annotation[] annotations = parameterAnnotations[i];
            boolean hasRequestBodyAnnotation = Arrays.stream(annotations).anyMatch(annotation -> annotation.annotationType().equals(RequestBody.class));
            if (hasRequestBodyAnnotation) {
                // 捕获携带@RequestBody注解的参数,供签名校验使用
                bodyParam = arg;
            }
        }
        // update-end-----author:sjlei---date:20260115 for: 查找带有@RequestBody注解的参数,解决签名校验时读取请求体为空的问题

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            log.error("无法获取请求上下文");
            throw new IllegalArgumentException("无法获取请求上下文");
        }
        
        HttpServletRequest request = attributes.getRequest();
        log.info("X-SIGN: {}, X-TIMESTAMP: {}", request.getHeader("X-SIGN"), request.getHeader("X-TIMESTAMP"));
        
        try {
            // 直接调用SignAuthInterceptor的验证逻辑
            signAuthInterceptor.validateSignature(request, bodyParam);
            log.info("AOP签名验证通过");
            
        } catch (IllegalArgumentException e) {
            // 使用注解中配置的错误消息,或者保留原始错误消息
            String errorMessage = signatureCheck.errorMessage();
            log.error("AOP签名验证失败: {}", e.getMessage());
            
            if ("Sign签名校验失败!".equals(errorMessage)) {
                // 如果是默认错误消息,使用原始的详细错误信息
                throw e;

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Ensure @SignatureCheck methods are only invoked within HTTP request threads — do not call them from async/scheduled/background code.
  2. If the method must be callable from both web and non-web contexts, remove @SignatureCheck and apply signature validation conditionally.
  3. For async processing that needs request context, use RequestContextHolder.setRequestAttributes(attrs, true) to propagate, or pass the request data explicitly.
  4. In tests, use MockMvc or set up RequestContextHolder with a MockHttpServletRequest before invoking.

Example fix

// before — @SignatureCheck method called from async context
@Async
public void processData(SignedRequest req) {
    myController.signedMethod(req); // triggers aspect, no request context
}

// after — propagate request context or extract validation
@Async
public void processData(SignedRequest req, ServletRequestAttributes attrs) {
    RequestContextHolder.setRequestAttributes(attrs, true);
    myController.signedMethod(req);
}
// Or: perform signature validation before entering async, not inside it.
Defensive patterns

Strategy: validation

Validate before calling

// Before calling a @SignatureCheck method from non-web context:
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs == null) {
    // do not call the signed method, or set up context first
    return;
}

Type guard

private static boolean hasRequestContext() {
    return RequestContextHolder.getRequestAttributes() != null;
}

Try / catch

try {
    // call @SignatureCheck method
} catch (IllegalArgumentException e) {
    if ("无法获取请求上下文".equals(e.getMessage())) {
        log.error("SignatureCheck invoked outside HTTP request thread");
    }
    throw e;
}

Prevention

When it happens

Trigger: A @SignatureCheck-annotulated method is called from a non-web thread (e.g., @Async method, scheduled Quartz job, message listener, or internal service-to-service call); the RequestContextHolder has not been configured to inherit child threads (RequestContextListener or RequestContextHolder.setInheritableThreadLocal(true) not set); the aspect is accidentally triggered during unit testing without a mock request context.

Common situations: A @SignatureCheck method is called from a background thread or async handler; an integration test invokes the controller method directly without setting up MockHttpServletRequest; the method is invoked from a message-driven bean (RabbitMQ/Kafka listener) that has no HTTP context.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/c9e0156d384ee475. Report an issue: GitHub.