如何忽略 Spring @RestController 上的任何 http 内容 headers?
How to ignore any http content headers on Spring @RestController?
我有一些 webservice
端点应该默认提供 json
数据。因此配置如下:
@Configuration
public class ContentNegotiationConfiguration implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
问题:现在我想创建一个提供文件下载的端点(因此不是 json)。
@RestController
public class FileServlet {
@GetMapping(value = "/docs/{filename}", consumes = MediaType.ALL_VALUE, produces = APPLICATION_OCTET_STREAM_VALUE)
public Object download(@Pathvariable filename) {
File file = fileservice.resolve(filename);
return new FileSystemResource(file);
}
}
从浏览器访问这个端点工作正常。我可以下载文件。
但是:当使用未设置任何 http headers(如 content-type、accept-header 等)的本机客户端时,访问失败并显示:
WARN o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver: Resolved
[org.springframework.web.HttpMediaTypeNotAcceptableException:
Could not find acceptable representation]
所有这些都导致异常:
curl localhost:8080/docs/testfile.txt
curl -O localhost:8080/docs/testfile.txt
wget localhost:8080/docs/testfile.txt
这可能是因为我在上面ContentNegotiationConfiguration
中将默认内容类型设置为json
。由于默认情况下应为 json 的所有其他端点,我无法更改它。
问题:如何显式忽略该单一端点 上的默认json 设置,并始终只提供下载流?
尝试使用 AntPathMatcher 自定义 ContentNegotiationStrategy,例如:
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// configurer.defaultContentType(MediaType.APPLICATION_JSON,MediaType.APPLICATION_OCTET_STREAM);
configurer.defaultContentTypeStrategy(
new ContentNegotiationStrategy() {
private UrlPathHelper urlPathHelper = new UrlPathHelper();
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request == null) {
return null;
}
String path = this.urlPathHelper.getLookupPathForRequest(request);
if (antPathMatcher.match("/docs/*", path)) {
return Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM);
} else {
return Collections.singletonList(MediaType.APPLICATION_JSON);
}
}
});
}
根据@M的提示。 Deinum,我的工作方式如下:
@GetMapping(value = "/docs/{filename}")
public void download(@Pathvariable filename) {
FileSystemResource file = new FileSystemResource(fileservice.resolve(filename));
rsp.setHeader("Content-Disposition", "attachment; filename=" + file.getFilename());
ResourceHttpMessageConverter handler = new ResourceHttpMessageConverter();
handler.write(file, MediaType.APPLICATION_OCTET_STREAM, new ServletServerHttpResponse(rsp));
}
这种方式绕过内容协商直接写入流,同时仍然依赖 Spring class ResourceHttpMessageConverter
不必自己实现响应编写器。
我有一些 webservice
端点应该默认提供 json
数据。因此配置如下:
@Configuration
public class ContentNegotiationConfiguration implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
问题:现在我想创建一个提供文件下载的端点(因此不是 json)。
@RestController
public class FileServlet {
@GetMapping(value = "/docs/{filename}", consumes = MediaType.ALL_VALUE, produces = APPLICATION_OCTET_STREAM_VALUE)
public Object download(@Pathvariable filename) {
File file = fileservice.resolve(filename);
return new FileSystemResource(file);
}
}
从浏览器访问这个端点工作正常。我可以下载文件。
但是:当使用未设置任何 http headers(如 content-type、accept-header 等)的本机客户端时,访问失败并显示:
WARN o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver: Resolved
[org.springframework.web.HttpMediaTypeNotAcceptableException:
Could not find acceptable representation]
所有这些都导致异常:
curl localhost:8080/docs/testfile.txt
curl -O localhost:8080/docs/testfile.txt
wget localhost:8080/docs/testfile.txt
这可能是因为我在上面ContentNegotiationConfiguration
中将默认内容类型设置为json
。由于默认情况下应为 json 的所有其他端点,我无法更改它。
问题:如何显式忽略该单一端点 上的默认json 设置,并始终只提供下载流?
尝试使用 AntPathMatcher 自定义 ContentNegotiationStrategy,例如:
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// configurer.defaultContentType(MediaType.APPLICATION_JSON,MediaType.APPLICATION_OCTET_STREAM);
configurer.defaultContentTypeStrategy(
new ContentNegotiationStrategy() {
private UrlPathHelper urlPathHelper = new UrlPathHelper();
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request == null) {
return null;
}
String path = this.urlPathHelper.getLookupPathForRequest(request);
if (antPathMatcher.match("/docs/*", path)) {
return Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM);
} else {
return Collections.singletonList(MediaType.APPLICATION_JSON);
}
}
});
}
根据@M的提示。 Deinum,我的工作方式如下:
@GetMapping(value = "/docs/{filename}")
public void download(@Pathvariable filename) {
FileSystemResource file = new FileSystemResource(fileservice.resolve(filename));
rsp.setHeader("Content-Disposition", "attachment; filename=" + file.getFilename());
ResourceHttpMessageConverter handler = new ResourceHttpMessageConverter();
handler.write(file, MediaType.APPLICATION_OCTET_STREAM, new ServletServerHttpResponse(rsp));
}
这种方式绕过内容协商直接写入流,同时仍然依赖 Spring class ResourceHttpMessageConverter
不必自己实现响应编写器。