Spring Boot+Tomcat10.1下WebdavServlet只读异常排查
Spring Boot 3.4.3+ 下WebDAV写入失败的只读问题
问题场景与配置
我在Spring应用中暴露了WebDAV Servlet,原配置如下:
@Bean public ServletRegistrationBean<MyWebdavServlet> servletWebdav() { final var servletRegistrationBean = new ServletRegistrationBean<>( new MyWebdavServlet(), "/webdav/*" ); servletRegistrationBean.setLoadOnStartup(0); servletRegistrationBean.addInitParameter("listings", "true"); servletRegistrationBean.addInitParameter("readonly", "false"); return servletRegistrationBean; } @Bean public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() { return factory -> { if (factory instanceof TomcatServletWebServerFactory tomcat) { documentRoot.mkdirs(); tomcat.setDocumentRoot(documentRoot); } else { throw new RuntimeException("Unsupported webserver : " + factory); } }; }
MyWebdavServlet是org.apache.catalina.servlets.WebdavServlet的扩展,仅在doHead和doPut方法中调用父类实现后执行额外操作。
在Spring Boot 3.4.3及对应新版本Tomcat发布前,该配置运行完全正常。但在Tomcat和Spring的相关变更后,WebDAV无法写入,资源被判定为只读。
即使在MyWebdavServlet中重写isReadOnly方法并固定返回false,问题仍无法解决——核心原因是DirResourceSet被设置为只读状态。当Servlet执行doPut时,DefaultServlet#doPut中的以下语句执行失败,返回409错误码:
if (this.resources.write(path, resourceInputStream, true)) {
目前未找到合理的配置方式来取消该资源的只读限制。
临时不规范解决方案
目前找到的唯一可行方式是通过反射修改,但这种方法并不规范:
public class MyWebdavServlet extends WebdavServlet { @Override protected boolean isReadOnly() { return false; } @Override public void init() throws ServletException { super.init(); removeReadOnlyOnMainResource(); } private void removeReadOnlyOnMainResource() { try { var mainField = StandardRoot.class.getDeclaredField("main"); mainField.setAccessible(true); var mainObject = mainField.get(super.resources); var setReadOnlyMethod = mainObject.getClass().getMethod("setReadOnly", boolean.class); setReadOnlyMethod.setAccessible(true); setReadOnlyMethod.invoke(mainObject, false); } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) { // 异常处理 } } }
内容的提问来源于stack exchange,提问作者Thoomas
相关产品推荐
相关产品推荐

