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

如何在Quarkus的CDI Bean中获取请求HttpHeaders,以获取AcceptableLanguage头进行翻译语言选择?

在Quarkus中让任意Bean访问请求的HttpHeaders

你遇到的这个问题核心在于Bean作用域不匹配:@ApplicationScoped的Bean是单例,它的生命周期远长于单个HTTP请求,初始化的时候根本没有请求上下文,所以直接用@Context注入HttpHeaders自然会得到null。而JAX-RS控制器(资源类)默认是请求作用域的,所以注入能正常工作。

下面给你几个可行的解决方案,你可以根据自己的需求选择:

方案一:将TranslationService改为请求作用域(最简单)

如果你的TranslationService不需要保持单例状态,直接把@ApplicationScoped换成@RequestScoped,@Context就能正常注入请求级别的HttpHeaders了:

import javax.ws.rs.core.HttpHeaders;
import javax.enterprise.context.RequestScoped;

@RequestScoped
public class TranslationService {
    @Context 
    HttpHeaders httpHeaders;

    public String getPreferredLanguage() {
        return httpHeaders.getAcceptableLanguages().stream()
                .findFirst()
                .map(lang -> lang.getLanguage())
                .orElse("en");
    }
}

方案二:用请求作用域Holder + Provider保留单例服务

如果必须让TranslationService保持@ApplicationScoped,可以通过一个请求作用域的Holder Bean来传递HttpHeaders,再用Provider延迟获取:

1. 创建请求作用域的HeadersHolder

import javax.ws.rs.core.HttpHeaders;
import javax.enterprise.context.RequestScoped;

@RequestScoped
public class HeadersHolder {
    private HttpHeaders httpHeaders;

    public void setHttpHeaders(HttpHeaders httpHeaders) {
        this.httpHeaders = httpHeaders;
    }

    public HttpHeaders getHttpHeaders() {
        return httpHeaders;
    }
}

2. 用过滤器设置Holder的值

创建一个JAX-RS过滤器,在请求到达时把当前的HttpHeaders存入Holder:

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.inject.Inject;
import javax.ws.rs.ext.Provider;

@Provider
public class RequestHeadersFilter implements ContainerRequestFilter {

    @Inject
    HeadersHolder headersHolder;

    @Context
    HttpHeaders httpHeaders;

    @Override
    public void filter(ContainerRequestContext requestContext) {
        // 两种方式都可以:用注入的HttpHeaders,或者从requestContext获取
        headersHolder.setHttpHeaders(httpHeaders);
    }
}

3. 在单例服务中通过Provider获取Holder

注意这里必须用Provider<HeadersHolder>而不是直接注入HeadersHolder——因为单例Bean初始化时请求上下文还不存在,Provider会在你调用get()时才从当前请求上下文获取实例:

import javax.ws.rs.core.HttpHeaders;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.enterprise.inject.Provider;

@ApplicationScoped
public class TranslationService {

    @Inject
    Provider<HeadersHolder> headersHolderProvider;

    public String getPreferredLanguage() {
        HttpHeaders httpHeaders = headersHolderProvider.get().getHttpHeaders();
        return httpHeaders.getAcceptableLanguages().stream()
                .findFirst()
                .map(lang -> lang.getLanguage())
                .orElse("en");
    }
}

方案三:直接在方法参数中注入请求上下文

如果你的TranslationService只会在处理JAX-RS请求时被调用,还可以直接在服务方法中注入ContainerRequestContext(它包含了所有请求头信息):

import javax.ws.rs.core.ContainerRequestContext;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.core.Context;

@ApplicationScoped
public class TranslationService {

    public String getPreferredLanguage(@Context ContainerRequestContext requestContext) {
        return requestContext.getAcceptableLanguages().stream()
                .findFirst()
                .map(lang -> lang.getLanguage())
                .orElse("en");
    }
}

之后在JAX-RS控制器中调用这个方法时,Quarkus会自动把当前请求的ContainerRequestContext注入进去。

至于你之前尝试用过滤器保存到@RequestScoped Bean却失败的原因,大概率是直接把@RequestScoped Bean注入到了@ApplicationScoped的TranslationService中——这种情况下注入的是一个代理,但如果在请求上下文外调用会出错,或者没有正确拿到当前请求的实例,用Provider就能解决这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:57:40