当 Netflix Feign 发送请求和接收响应时,需要对请求和响应的数据进行编码和解码。默认情况下,Netflix Feign 使用一些内置的编码器和解码器,如 JacksonEncoder 和 JacksonDecoder,但在某些场景下,我们可能需要自定义编码和解码的逻辑。下面将介绍如何自定义编码器和解码器:
要自定义编码器,需要实现 feign.codec.Encoder 接口。这个接口有一个 encode 方法,它接受三个参数:
void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException;
其中:
object 要编码的对象Object。
template 请求模板 RequestTemplate。
bodyType 请求的类型 Type。
例如,假设我们要自定义一个编码器,将一个自定义的 User 对象编码为 JSON 格式并发送到服务端。首先,我们需要定义 User 类:
Feign.builder()
.encoder(new Encoder() {
@Override
public void encode(Object o, Type type, RequestTemplate requestTemplate) throws EncodeException {
if(Objects.nonNull(o)) {
requestTemplate.body(JSONObject.toJSONString(o));
} else {
requestTemplate.body("");
}
}
})
.contract(new Contract.Default())
.target(EncodeDecodeFeign.class, "http://localhost:8090");自定义解码器需要实现 feign.codec.Decoder 接口。这个接口有一个 decode 方法,它接受三个参数:
Object decode(Response response, Type type) throws IOException, DecodeException, FeignException;
其中:
response 响应体Response。
type 类型Type。
例如,假设服务端返回的 JSON 数据中包含一些额外的字段或者格式与默认的不同,我们需要自定义解码器来正确解析数据。以下是一个简单的自定义解码器示例,用于将 JSON 数据解析为 User 对象:
Feign.builder()
.decoder(new Decoder(){
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(response.body().asInputStream().readAllBytes());
String body = outputStream.toString(StandardCharsets.UTF_8);
if (StringUtils.hasText(body)) {
return JSONObject.parseObject(body, Class.forName(type.getTypeName()));
} else {
return null;
}
} catch (Exception e) {
throw new DecodeException(response.status(), "Failed to decode response body: "
+ e.getMessage(), response.request(), e);
}
}
})
.contract(new Contract.Default())
.target(EncodeDecodeFeign.class, "http://localhost:8090");下面是自定义编码和解码器示例的完整代码:
(1)服务接口代码:
@PostMapping("/encode")
public User encode(@RequestBody User user) {
System.out.println(user);
return user;
}(2)定义 Feign 客户端:
package com.hxstrive.demo_netflix_feign.feign;
import com.alibaba.fastjson.JSONObject;
import com.hxstrive.demo_netflix_feign.entity.User;
import feign.*;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import org.springframework.util.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* 请求编码/解码器
* @author HuangXin
* @since 1.0.0 2024/11/1 16:34
*/
public interface EncodeDecodeFeign {
@RequestLine("POST /simple/encode")
@Headers("Content-Type: application/json")
User encode(User user);
// 自定义编码/解码器
static EncodeDecodeFeign create() {
return Feign.builder()
.encoder(new Encoder() {
@Override
public void encode(Object o, Type type, RequestTemplate requestTemplate) throws EncodeException {
if(Objects.nonNull(o)) {
requestTemplate.body(JSONObject.toJSONString(o));
} else {
requestTemplate.body("");
}
}
})
.decoder(new Decoder(){
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(response.body().asInputStream().readAllBytes());
String body = outputStream.toString(StandardCharsets.UTF_8);
if (StringUtils.hasText(body)) {
return JSONObject.parseObject(body, Class.forName(type.getTypeName()));
} else {
return null;
}
} catch (Exception e) {
throw new DecodeException(response.status(), "Failed to decode response body: "
+ e.getMessage(), response.request(), e);
}
}
})
.contract(new Contract.Default())
.target(EncodeDecodeFeign.class, "http://localhost:8090");
}
}(3)调用 Feign 客户端:
@GetMapping("/")
public String index() {
return EncodeDecodeFeign.create().encode(User.builder().id(100L).name("Tom").age(20).build()).toString();
}输出结果如下图:
