Netflix Feign 自定义编码/解码器

当 Netflix Feign 发送请求和接收响应时,需要对请求和响应的数据进行编码和解码。默认情况下,Netflix Feign 使用一些内置的编码器和解码器,如 JacksonEncoder 和 JacksonDecoder,但在某些场景下,我们可能需要自定义编码和解码的逻辑。下面将介绍如何自定义编码器和解码器:

自定义编码器(Encoder)

要自定义编码器,需要实现 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");

自定义解码器(Decoder)

自定义解码器需要实现 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();
}

输出结果如下图:

84daca88d562515db76569d5806cfffb_1730703521128-6e1b8b1e-15f4-44bc-8fe6-b2a29f3c33ab.png


说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号