Spring Cloud Open Feign:ByteArrayResource 的解码器

Spring Cloud Open Feign: Decoder for ByteArrayResource

我在界面中定义了一个 Spring Boot Rest End Point 来下载图像

@GetMapping(value = "/{name}")
ResponseEntity<ByteArrayResource> getFileByName(@PathVariable("name") String name);

并且我使用 Feign Builder 来调用这个端点。

Feign.builder()
    .client(new ApacheHttpClient())
    .contract(new SpringMvcContract())
    .decoder(new JacksonDecoder())
    .encoder(new JacksonEncoder())  
    .target(clazz, url)

调用时出现以下错误

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('�' (code 65533 / 0xfffd)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
 at [Source: (BufferedReader); line: 1, column: 2]

当我尝试直接从 Insomnia 调用终点时,它工作正常。但是通过 Feign Builder 失败了。响应内容类型为image/jpeg

是否有任何特定的解码器假装处理 ByteArrayResource?我尝试了 ResponseEntityDecoderStreamDecoderJacksonDecoder。 None 有效。

调试时,我看到 Jackson ObjectMapper readValue 失败。我尝试将 return 类型从 ByteArraySource 更改为 byte[],也没有用。

有什么帮助吗?

我自己写了个小解码器,问题解决了。下面是解码器

private Decoder byteArrayResourceDecoder() {
        Decoder decoder = (response, type) -> {
            if (type instanceof Class && ByteArrayResource.class.isAssignableFrom((Class) type)) {
                return StreamUtils.copyToByteArray(response.body().asInputStream());
            }
            return new JacksonDecoder().decode(response, type);
        };

        return new ResponseEntityDecoder(decoder);
    }

希望此模板对遇到类似问题的其他人有所帮助。本来期望 Feign 有支持所有 return 类型的解码器。

谢谢 Maz - 你的解决方案对我有帮助。

我根据阅读需要修改了您的解决方案Spring StreamingResponseBody

1.) 创建解码器包装器 returns JacksonDecoder(默认)或将 responsebody 读入字节数组。

Decoder decoder = (response, type) -> {
                
                Map<String, Collection<String>> headers = response.headers();
                Collection<String> contentType = null;
                for (String x : headers.keySet()){
                    if ("content-type".equals(x.toLowerCase())){
                        contentType = headers.get(x);                      
                    } 
                }

                if (contentType == null || contentType.stream().filter(x -> x.contains("application/json")).findFirst().isPresent()) {                    
                    return new JacksonDecoder(getMapper()).decode(response, type);
                }

                InputStream initialStream = response.body().asInputStream();
                byte[] buffer = new byte[512];
                byte[] result = null;

                try(ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                    try {
                        int length = 0;
                        while ((length = initialStream.read(buffer)) != -1) {
                            out.write(buffer, 0, length);
                        }
                    } finally {
                        out.flush();
                    }
                    result = out.toByteArray();
                } finally {
                    initialStream.close();
                }

                return result;
            };

2.) 使用带有 Feign.Builder

的自定义解码器
Feign.Builder builder = Feign.builder()
                    // --
                    .decoder(decoder)
                    // --