You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 03:27:26