需求描述

在微服务项目中,需要请求第三方接口,通常情况下我们使用 spring 的 restTemplate。但接触到 feign 之后,这种将远程方法伪装成本地接口,屏蔽请求感知的方式,无疑更优雅。
但对于 oauth 认证,需要配置请求头,即设置 feign 的自定义配置。

自定义授权头信息

请求远程连接

@FeignClient 用于注册接口为 feign 客户端,在 spring cloud 项目中,需要在其 value(或 name)属性中指定对应的微服务名,url 置空(将自动匹配配置中西地址)。当需要调用任意的 http 请求时,只要给定 url 值即可。
注意 :此时,虽然不是请求微服务接口,仍然需要设置 name,填写任意(不冲突的)名称即可。

授权流程

授权配置

需要通过自定义配置属性来指定请求头,对应 @FeignClient 的 configuration 属性。
该属性指定一个自定义配置类,用于设置 feign 的任意配置。

Basic 认证

1
2
3
4
5
6
7
8
9
10
11
12
13
// @Configuration 托管给 spring 之后,会被注册为全局配置
// 局部配置需要指定在 @FeignClient(configuration = SomeAuthConfig.class)
public class SomeAuthConfig {

@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(SomeProperties someProperties) {
// someProperties 是一个属性类
return new BasicAuthRequestInterceptor(
someProperties.getAuth().getUser(),
someProperties.getAuth().getPassword()
);
}
}

请求 token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@FeignClient(
name = "some-auth", url = "${some.auth.url}",
configuration = SomeAuthConfig.class
)
public interface SomeAuthIntegration {

/**
* 获取 token
*
* @return 授权信息
*/
@PostMapping(value = "/xxx")
SomeAuthResponse getToken();

}

设置 Authorization Header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SomeTokenConfig {

/**
* 配置 header auth
*
* @param authIntegration 授权接口
* @return 请求拦截器
*/
@Bean
public RequestInterceptor requestInterceptor(SomeAuthIntegration authIntegration) {
// 此处使用的是 lambda 表达式返回一个实现 RequestInterceptor 的匿名类,
// 在 lambda 表达式外部的操作会在 bean 注册时生效,
// 因此,每次获取 token 的操作,应该放在表达式内部
return requestTemplate -> {
SomeAuthResponse authResponse = authIntegration.getToken();
requestTemplate.header(
AUTHORIZATION,
StrUtil.format("{} {}", authResponse.getTokenType(), authResponse.getAccessToken())
);
};
}
}

已授权请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@FeignClient(
name = "some-reply", url = "${some.reply.url}",
configuration = SomeTokenConfig.class
)
public interface SomeReplyIntegration {

/**
* 回传状态
*
* @param status 状态信息
*/
@PostMapping("/xxx")
void apply(SomeStatus status);

}

自定义解码器

当响应信息实际返回的是 json 格式,但头信息描述类型是 Content-Type: text/xml;charset=utf-8 (或其他非 *application/json *类型)时,feign 的默认消息转换器无法解析,此时就需要重新使用自定义解码器。
在配置类中注册 Decoder bean。

1
2
3
4
5
6
7
8
9
10
@Bean
public Decoder someResponseDecoder() {
return new SpringDecoder(() -> new HttpMessageConverters(
new MappingJackson2HttpMessageConverter() {
{
setSupportedMediaTypes(Lists.newArrayList(MediaType.TEXT_XML));
}
}
));
}

其他

feing 基于 http 请求,在其配置类中,可以实现任意 http 的相关配置,包括超时时间、重试次数等。
一般情况下,accessToken 存在过期时间,为了防止频繁请求授权,应该在过期之前进行缓存。

评论