gpt4 book ai didi

spring-mvc - SpringMVC : Inconsistent mapping behavior depending on url extension

转载 作者:行者123 更新时间:2023-12-03 13:31:32 25 4
gpt4 key购买 nike

我有一个基于RESTful spring的终结点,可以将存储在数据库中的 Assets 获取到javascript编辑器。相关部分归结为:

@RestController
@RequestMapping(ThemeEndpoint.ENDPOINT_NAME)
public class ThemeEndpoint {

public static final String ENDPOINT_NAME = "/themes";

@RequestMapping(value="/{id}/css/{assetName:.*}", method=RequestMethod.GET)
public Asset getCssItem(
@PathVariable("id") ThemeId id,
@PathVariable("assetName") String name) {
CssThemeAsset themeAsset = themeService.getCssAsset(
id, ThemeAssetId.fromString(name));
Asset asset = new Asset();
asset.name = themeAsset.getName();
asset.text = themeAsset.getContent();
return asset;
}

对于像这样的网址,这可以正常工作
http://localhost:8080/app-url/rest/themes/ac18a080-a2f1-11e3-84f4-600308a0bd14/css/main.less

但是在我将扩展名更改为 .css时失败。

经过一些调试后,我很确定如果我使用类似url的请求,甚至不会映射该请求
http://localhost:8080/app-url/rest/themes/ac18a080-a2f1-11e3-84f4-600308a0bd14/css/main.css

在高日志级别下,我可以看到映射已被spring捕获:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 
- Mapped "{[/themes/{id}/css/{assetName:.*}],methods=[GET],params=[],headers=[],
consumes=[],produces=[application/json],custom=[]}"
onto public xxx.endpoint.ThemeEndpoint$Asset
xxx.endpoint.ThemeEndpoint.getCssItem(
net.lacho.svc.themes.api.ThemeId,java.lang.String)

使用非.css扩展名的 Controller 称为:
Found 1 matching mapping(s) for [/themes/ac18a080-a2f1-11e3-84f4-600308a0bd14/css/main.less]
: [{[/themes/{id}/css/{assetName:.*}],methods=[GET],params=[],headers=[],
consumes=[],produces=[application/json],custom=[]}]

但是,一旦我使用.css作为扩展名-爆炸:
Looking up handler method for path /themes/ac18a080-a2f1-11e3-84f4-600308a0bd14/css/test.css
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver -
Resolving exception from handler [null]:
org.springframework.web.HttpMediaTypeNotAcceptableException:
Could not find acceptable representation
web.xml和MVC-Config根据要求:

web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="false">

<welcome-file-list>
<welcome-file>index</welcome-file>
</welcome-file-list>

</web-app>

WebApplicationInitializer:
package net.lacho.opcenter.bootstrap;


public class WebApplicationBootstrapper implements WebApplicationInitializer {


@Override
public void onStartup(ServletContext container) throws ServletException {

AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.setConfigLocation(ApplicationConfig.class.getName());

container.addListener(new ContextLoaderListener(rootContext));

registerRestDispatcher(container);
registerDefaultDispatcher(container);

container.addFilter("CharacterEncodingFilter", UTF8EncodingFilter.class).addMappingForUrlPatterns(null, true, "/*");
container.addFilter("headSupportFilter", HeadSupportFilter.class).addMappingForUrlPatterns(null, true, "/*");

DelegatingFilterProxy shallowFrontendContextFilterProxy = new DelegatingFilterProxy("shallowFrontendContextProviderLocalFilter");
shallowFrontendContextFilterProxy.setTargetFilterLifecycle(true);
FilterRegistration.Dynamic shallowFrontendFilter = container.addFilter("ShallowFrontendContextFilter", shallowFrontendContextFilterProxy);
shallowFrontendFilter.setInitParameter("ignoreNullClient", "true");
shallowFrontendFilter.addMappingForUrlPatterns(null, true, "/*");

container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, true, "/*");

container.addFilter("FrontendContextFilter", new DelegatingFilterProxy("frontendContextProviderLocalFilter"))
.addMappingForUrlPatterns(null, true, "/*");

container.addFilter("hiddenHttpMethodFilter", new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null, true, "/rest/*");;
}

public void registerRestDispatcher(ServletContext container) {
AnnotationConfigWebApplicationContext restDispatcherContext = new AnnotationConfigWebApplicationContext();
restDispatcherContext.register(RestCommonsMvcConfig.class);

ServletRegistration.Dynamic restDispatcher = container.addServlet("rest-dispatcher", new DispatcherServlet(restDispatcherContext));
restDispatcher.setLoadOnStartup(1);
restDispatcher.addMapping("/rest/*");
}

public void registerDefaultDispatcher(ServletContext container) {
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(MvcConfig.class);

ServletRegistration.Dynamic dispatcher = container.addServlet("backend-dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*", "/index");
}

}

MVC配置:
package net.lacho.opcenter.bootstrap;



@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"net.lacho.opcenter.ui"} )
public class MvcConfig extends WebMvcConfigurerAdapter {

... many lines removed, containing interceptors and velocity-config ...

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/_r/_s/**")
.addResourceLocations("classpath:/static-resources/")
.setCachePeriod(365 * 86400);
registry
.addResourceHandler("/_r/_d/**")
.addResourceLocations("classpath:/static-uncached-resources/");
}

@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

有人知道吗?

最佳答案

这不是一个错误,这是一个功能...

正如@axtavt和@rhinds所假定的那样,内容类型周围有些困惑。浏览器发送了正确的Accept: application/json,但是spring忽略了它,并使用url的扩展名(aarrgh)。从文档中:

16.16.4 Configuring Content Negotiation

You can configure how Spring MVC determines the requested media types from the client for
request mapping as well as for content negotiation purposes. The available options are to
check the file extension in the request URI, the "Accept" header, a request parameter, as
well as to fall back on a default content type. By default, file extension in the request
URI is checked first and the "Accept" header is checked next.


解决方案非常简单,因为您可以禁用此“功能”:
@Configuration
@EnableWebMvc
public class RestCommonsMvcConfig extends WebMvcConfigurerAdapter {

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}

}

另请参阅 Spring does not ignore file extension以获取xml-config。

有关的
  • Spring MVC @PathVariable with dot (.) is getting truncated
  • 关于spring-mvc - SpringMVC : Inconsistent mapping behavior depending on url extension,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22329393/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com