我在 Spring Boot API 中使用 Feign,我想使用以下内容对其进行配置:
import feign.RequestInterceptor;
import feign.auth.BasicAuthRequestInterceptor;
import feign.codec.ErrorDecoder;
import feign.okhttp.OkHttpClient;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfiguration {
@Bean
public ErrorDecoder errorDecoder() {
return new ErrorDecoder.Default();
}
@Bean
public OkHttpClient client() {
return new OkHttpClient();
}
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
requestTemplate.header("user", "some user");
requestTemplate.header("password", "some password");
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
};
}
}
问题是,如果我在服务中使用以下代码,我会收到 401,似乎没有提供身份验证数据:
Feign.builder()
.client(new OkHttpClient())
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.logger(new Slf4jLogger(Npa.class))
.target(AClass.class, "https://some.website");
如果我只添加一行指定用户和密码,它就可以工作:
Feign.builder()
.client(new OkHttpClient())
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.logger(new Slf4jLogger(Npa.class))
.requestInterceptor(new BasicAuthRequestInterceptor("some user", "some password"))
.target(AClass.class, "https://some.website");
我更愿意使用该配置,但我不明白其中有什么问题。
最佳答案
由于您已经创建了一些 Bean,因此您无需在构建器步骤中再次手动实例化它们。
您可以在其中创建假客户端的伪类可能如下所示:
@Component
public class FeignClientFactory {
@Autowired
private ErrorDecoder errorDecoder;
@Autowired
private OkHttpClient client;
@Autowired
private RequestInterceptor requestInterceptor;
public AClass getFeignClient() {
return Feign.builder()
.client(client)
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.logger(new Slf4jLogger(Npa.class))
.requestInterceptor(requestInterceptor)
.target(AClass.class, "https://some.website");
}
}
当然,有很多改进的选择。例如,您可以创建其他 bean(用于编码器、记录器等)或使用默认(自动配置)的 bean。
或者,如果您只需要一个假客户端 bean,则可以在 @Configuration
类中执行此操作。
对于请求拦截器 - 还有另一个构建器步骤 .requestInterceptors
,您可以在其中传递它们的集合。
编辑:对于基本身份验证,您不需要单独的用户名和密码 header ,而是需要一个 header “授权”。它的值应类似于“Basic username:password”,其中“username:password”部分应使用 Base64 进行编码 ( link )。
因此,在您的 @Configuration
类中,您可以这样编写:
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
String encodedCredentials = Base64.getEncoder()
.encodeToString("some user:some password".getBytes());
requestTemplate.header("Authorization", "Basic " + encodedCredentials);
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
};
}
然后您可以使用这个 bean 来构建 Feign 客户端,如上所述。
另一个选项:因为创建授权 header 是一项非常常见的任务,所以 Feign 引入了 BasicAuthRequestInterceptor
来执行相同的操作。你可以用它来代替。现在,在 @Configuration
类中,您可以创建两个 bean:
@Bean
@Qualifier("basicAuthRequestInterceptor")
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("some user","some password");
}
@Bean
@Qualifier("customRequestInterceptor")
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
};
}
在这种情况下,您需要修改 feign 客户端构建方法才能应用这两个拦截器:
@Component
public class FeignClientFactory {
@Autowired
private ErrorDecoder errorDecoder;
@Autowired
private OkHttpClient client;
@Autowired
@Qualifier("basicAuthRequestInterceptor")
private RequestInterceptor basicAuthRequestInterceptor;
@Autowired
@Qualifier("customRequestInterceptor")
private RequestInterceptor requestInterceptor;
public AClass getFeignClient() {
List<RequestInterceptor> requestInterceptors = new ArrayList<>();
requestInterceptors.add(basicAuthRequestInterceptor);
requestInterceptors.add(requestInterceptor);
return Feign.builder()
.client(client)
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())
.logger(new Slf4jLogger(Npa.class))
.requestInterceptors(requestInterceptors)
.target(AClass.class, "https://some.website");
}
}
关于java - Feign 配置未被使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61330274/