我正在尝试构建一个Spring控制器,它实际上充当Geoserver示例的反向代理。例如,如果客户端想要访问geoserver/wms?PARAM1=foo&PARAM2=bar
,控制器将简单地将请求转发到实际的Geoserver示例并返回响应。在我的例子中,Geoserver要么返回一个XML有效负载,要么返回一个图像。
在使用返回图像的URL测试此控制器时,我能够处理初始客户端请求,将其转发到Geoserver,然后进行处理,但在向客户端提供响应时出现以下错误:
There was an unexpected error (type=Internal Server Error, status=500).
No converter for [class [B] with preset Content-Type 'image/png'
org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class [B] with preset Content-Type 'image/png'
下面是控制器类:
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.BasePathAwareController;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.WebClient;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@BasePathAwareController
public class GeoServerProxyController {
//only used to check which converters are present
@Autowired
List<HttpMessageConverter<?>> converters;
@RequestMapping(value = "/geoserver/**")
@ResponseBody
public ResponseEntity<byte[]> forwardRequest(@RequestParam MultiValueMap<String, String> requestParams, @RequestHeader Map<String, String> headers, HttpServletRequest request) {
WebClient client = WebClient.builder()
.baseUrl("http://127.0.0.1:8090/geoserver/")
.build();
String url = new AntPathMatcher().extractPathWithinPattern("/geoserver/**", request.getRequestURI());
WebClient.ResponseSpec response = client.get()
.uri(uriBuilder -> uriBuilder
.path(url)
.queryParams(requestParams)
.build())
.headers(httpHeaders -> {
headers.forEach(httpHeaders::set);
})
.retrieve();
HttpHeaders responseHeaders = response.toBodilessEntity().map(HttpEntity::getHeaders).block();
byte[] responseBody = response.bodyToMono(byte[].class).block();
return ResponseEntity.ok().headers(responseHeaders).body(responseBody);
}
正如在另一个线程中所建议的,我已经尝试注册一个字节数组http消息转换器,我能够确认它已添加到http消息转换器列表中。
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
final List<MediaType> list = new ArrayList<>();
list.add(MediaType.IMAGE_JPEG);
list.add(MediaType.IMAGE_PNG);
list.add(MediaType.APPLICATION_OCTET_STREAM);
arrayHttpMessageConverter.setSupportedMediaTypes(list);
converters.add(arrayHttpMessageConverter);
}
}
这导致了相同的错误。
我还尝试按照this article的建议,使用dInputStreamResource
作为返回类型。除了使用InputStreamResource
而不是class [B]
之外,它会导致相同类型的错误。
我还尝试将以下注解添加到我的控制器方法中(这并不是最优的,因为我不希望指定常量内容类型):
@RequestMapping(value = "/geoserver/**", produces=MediaType.IMAGE_PNG_VALUE)
这也会导致完全相同的错误。
在其他帖子或Spring Web文档中,我找不到这个问题的解决方案。与此有些类似的最常见问题是处理“Content-Type=NULL”标头,这不是我的情况。
有人知道如何解决这个错误吗?或者,有没有更好的方式通过Spring控制器提供远程图像文件?
3条答案
按热度按时间ars1skjm1#
@ResponseBody
注解用于将Java对象序列化为响应(通常为JSON或XML)。在这里,您不想转换任何内容,只需要发送原始的二进制内容。删除注解。您还应该将
@RestController
更改为@Controller
,因为@RestController
会自动添加@ResponseBody
。2exbekwf2#
看起来您面临的问题是由于
@BasePathAwareController
造成的,移除它,您就可以开始工作了。描述:
基于共享的堆栈跟踪:
发生这种情况时,SpringDataRest正在尝试将适当的对象Map到它找不到的
content-type
。因此抛出一个通用的500异常。b4wnujal3#
对于那些感兴趣的人:我有过同样的问题,就像这样解决它。此代码不是最终代码,仅用于测试我的情况。
棱角前端开口层
瓷砖层:我定义了定制的tileLoadFunction(示例可以在Open Layers文档中找到),url调用我的SprringBoot后端API,其中代理Geoserver后端,在FETCH报头中发送JWT令牌(出于安全目的,非强制)
SpringBoot后端
我有一个RestController端点,它离第一个帖子很近,对我来说一切都很好:WMS Geoserver切片由我的前端调用,bakend拦截这些调用并发出Geoserver请求,最后将切片发送回前端,WMS图层显示在Map上