最近,前端nginx的日志一直在报一些URL的请求后端响应是500状态码,于是缓存其结果,可以看到一直是报一个 javax.servlet.ServletException: Could not resolve view with name 'xxxx'in servlet with name 'Spring MVC Dispatcher Servlet ‘的异常。
分析这些报这个异常的的URL,规则都是/xxx/{xxx},报错的URL都是类似于 /xxx/xxx.jpg之类的跟着后缀的,我们的资源内容中也就是这个路由是对应的是没有这个jpg的资源的,也就是说自然会是404,但是404竟然也报这个异常和500错误码。
看了springmvc关于这个异常的出处,很明显的是View为null,而view是由resolveViewName获得的。
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException(
"Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
getServletName() + "'");
}
}
......
}
我们接下来继续看resolveViewName实现。 protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
HttpServletRequest request) throws Exception {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
return null;
}
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.isInstanceOf(ServletRequestAttributes.class, attrs);
List<MediaType> requestedMediaTypes = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
if (requestedMediaTypes != null) {
List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = getBestView(candidateViews, requestedMediaTypes);
if (bestView != null) {
return bestView;
}
}
if (this.useNotAcceptableStatusCode) {
if (logger.isDebugEnabled()) {
logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
}
return NOT_ACCEPTABLE_VIEW;
}
else {
logger.debug("No acceptable view found; returning null");
return null;
}
}
我们看到了,是requestedMediaTypes为null引起的view为空,而requestedMediaTypes 通过getMediaTypes方法生成,看了里面的代码,才明白原来是springmvc会去判断URI的后缀,然后根据后缀去获取对应的mediatypes。jpg对应的mediatype是jpg/image。
因此找到原因了,我们的项目中,关于springmvc的viewresolve的配置,没有关于这个media的,所以去解析视图的时候无法解析。解决办法也很简单,直接加一个默认的viewsolve就OK了。
<!--通用视图解析器-->
<bean id="viewResolverCommon" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"/>
<property name="suffix" value=".jsp"/><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑 -->
<property name="viewClass">
<value>org.springframework.web.servlet.view.InternalResourceView</value>
</property>
<property name="order" value="1"/>
</bean>