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?我尝试了 ResponseEntityDecoder、StreamDecoder 和 JacksonDecoder。 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)
// --
我在界面中定义了一个 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?我尝试了 ResponseEntityDecoder、StreamDecoder 和 JacksonDecoder。 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)
// --