彻底搞定Window映射Nginx搭建的WebDav问题

前言

继前两篇文章,介绍了两种搭建WebDav的方法:

  • Apache2后端,Nginx反向代理

  • Nginx直接搭建WebDav

这两种方法都存在一个很大的问题,Windows磁盘映射会出现各种错误,而且还不是单一的错误,这两天操碎了心,国内国外文章全部扒了一遍又一遍,所幸最终还是可以解决的。

问题:

  1. 无法创建、上传文件(夹)

  2. 提示:目录内已经存在相同的文件,是否覆盖

  3. 遗留一个0KB 的空白文件

  4. 另一个程序已经锁定文件的一部分,无法访问

问题的核心是 Windows 自带的 WebDAV 客户端(Microsoft-WebDAV-MiniRedir)与服务器的 WebDAV 模块之间的兼容性问题

这个问题不单纯是Nginx或者Apache2,其实很多第三方应用也是一样,比如我尝试过的Openlist,Hfs,它们可能一些小文件上传下载没问题,但是由于我经常要传输蓝光电影,文件大点也是一样的错误。

根源的Windows磁盘映射在搞事情,我们只能顺着它的心意。

顺带说一句,MacOS也不比它好,测试下来半斤八两。

重点

基于前两篇文章已经配置成功并能正常访问,我们只谈一下后续的步骤。

之前正常访问的配置文件:(抛弃Apache2,只用Nginx)

# /etc/nginx/site-enable/wedav.conf
server {

    listen 80;
    listen [::]:80;

    server_name _;

    location / {
        root /path/to/your/folder;
        dav_methods PUT DELETE MKCOL COPY MOVE;
        dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
        dav_access group:rw all:r;
        autoindex on;
        auth_basic "WebDAV";
        auth_basic_user_file /etc/nginx/webdav.htpasswd;
        client_max_body_size 0;
        create_full_put_path on;
    }

}

此时,我们已经安装了 libnginx-mod-http-dav-ext 模块。

继续安装一个 http-headers-more-filter 模块:

apt install libnginx-mod-http-headers-more-filter

添加在 /etc/nginx/nginx.conf 的前端:

load_module modules/ngx_http_dav_ext_module.so; # 之前安装的
load_module modules/ngx_http_headers_more_filter_module.so; # 这次安装的

并且在 nginx.confhttp模块中添加一些配置参数:

http {
  dav_ext_lock_zone zone=foo:10m;  # 扩展锁定功能的内存区域
  client_max_body_size 0;
  create_full_put_path on;
  min_delete_depth 0;
  charset utf-8;
  source_charset utf-8;

  # 其他参数

}

然后编辑 /etc/nginx/site-enable/webdav.conf ,这部分仔细一些,一步步慢慢来。

# /etc/nginx/site-enable/wedav.conf
server {
    listen 80;
    listen [::]:80;

    server_name _;

    # 定义变量
    set $destination $http_destination;
    set $new_path "";
    set $webdav_root "/path/to/your/folder"; # 填写webdav路径
    set $checkPropfind "";

    #这个location块照抄就行,基本没有要改的东西
    location / {
        root $webdav_root;
        open_file_cache off;
        auth_basic "WebDAV";
        auth_basic_user_file /etc/nginx/webdav.htpasswd;

        dav_ext_lock zone=foo;
        dav_methods PUT DELETE MKCOL COPY MOVE;
        dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;

        autoindex on;
        autoindex_exact_size on;
        autoindex_localtime on;

        error_page      599 = @propfind_handler;
        error_page      598 = @delete_handler;
        error_page      597 = @copy_move_handler;
        error_page      596 = @propfind_withdepth_handler;

        if ($request_method != OPTIONS) {
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Access-Control-Allow-Methods' 'OPTIONS, GET, HEAD, POST, PUT, MKCOL, MOVE, COPY, DELETE, PROPFIND, PROPPATCH, LOCK, UNLOCK' always;
            add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite' always;
            add_header 'Access-Control-Expose-Headers' 'ETag' always;
            add_header 'Access-Control-Max-Age' 1728000 always;
        }

        if ($request_method = OPTIONS) {
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'OPTIONS, GET, HEAD, POST, PUT, MKCOL, MOVE, COPY, DELETE, PROPFIND, PROPPATCH, LOCK, UNLOCK';
            add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite';
            add_header 'Access-Control-Expose-Headers' 'ETag';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header  Allow 'OPTIONS, GET, HEAD, POST, PUT, MKCOL, MOVE, COPY, DELETE, PROPFIND, PROPPATCH, LOCK, UNLOCK';
            add_header  DAV '1, 2';
            return 200;
        }

        if ($request_method = PROPFIND) {
            set $checkPropfind "propfind";
        }

        if ($http_depth = 0) {
            set $checkPropfind "${checkPropfind}+withDepth";
        }

        if ($http_depth = 1) {
            set $checkPropfind "${checkPropfind}+withDepth";
        }

        if ($checkPropfind = "propfind") {
            return 599;
        }

        if ($checkPropfind = "propfind+withDepth") {
            return 596;
        }

        if ($request_method = PROPPATCH) {
            add_header  Content-Type 'text/xml';
            return      207 '<?xml version="1.0"?><a:multistatus xmlns:a="DAV:"><a:response><a:propstat><a:status>HTTP/1.1 200 OK</a:status></a:propstat></a:response></a:multistatus>';
        }

        if ($request_method = MKCOL) {
            rewrite ^(?<captured_path>.*[^/])$ $captured_path/ break;
        }
        if ($request_method = DELETE) {
            return 598;
        }
        if ($request_method = COPY) {
            return 597;
        }  
        if ($request_method = MOVE) {
            return 597;
        }
    } 

    # 这几个也不用修改
    location ~ \.(_.*|DS_Store|Spotlight-V100|TemporaryItems|Trashes|hidden|localized)$ {
        access_log off;
        error_log off;
        if ($request_method = PUT) {
            return 403;
        }
        return 404;
    }

    location ~ \.metadata_never_index$ {
        return 200 "Don't index this drive, Finder!";
    }

    location @propfind_handler {
        internal;
        open_file_cache off;
        if (!-e $webdav_root/$uri) {
            return 404;
        }
        root            $webdav_root;
        dav_ext_methods     PROPFIND;
    }

    # 下面几个location把前两行的身份认证统一一下

    location @propfind_withdepth_handler {
        auth_basic "WebDAV";
        auth_basic_user_file /etc/nginx/webdav.htpasswd;
        internal;
        open_file_cache off;

        if (!-e $webdav_root/$uri) {
            return 404;
        }
        root            $webdav_root;
        dav_ext_methods     PROPFIND;
    }

    location @delete_handler {
        auth_basic "WebDAV";
        auth_basic_user_file /etc/nginx/webdav.htpasswd;
        internal;
        open_file_cache off;

        if ($destination ~ ^https?://(?<captured_path>.*)$) {
            set $new_path $captured_path;
            more_set_input_headers "Destination: http://$new_path";
        }   

        if (-d $webdav_root/$uri) {
            more_set_input_headers "Destination: http://$new_path/";
            rewrite ^(?<captured_path>.*[^/])$ $captured_path/ break;
        }    
        root            $webdav_root;
        dav_methods     DELETE;
    }

    location @copy_move_handler {
        auth_basic "WebDAV";
        auth_basic_user_file /etc/nginx/webdav.htpasswd;
        internal;
        open_file_cache off;

        if ($destination ~ ^https?://(?<captured_path>.*)$) {
            set $new_path $captured_path;
            more_set_input_headers "Destination: http://$new_path";
        }

        if (-d $webdav_root/$uri) {
            more_set_input_headers "Destination: http://$new_path/";
            rewrite ^(?<captured_path>.*[^/])$ $captured_path/ break;
        }    
        root            $webdav_root;
        dav_methods     COPY MOVE;
    }

}

重启Nginx后重新映射一下,这次应该没有问题~

结论

结论放前面,这个方法有点麻烦!不建议使用Windows自带的磁盘映射挂载WevDav!

必须要挂载的,不用上面的操作,直接参考网上的建议:使用第三方软件(如 RaiDrive, NetDrive, CarotDAV)!

不过有一点就是比如RaiDrive以前没有广告的,现在开始有广告了。只能自行抉择了。

后话

Windows其实对SMB支持非常好,但是SMB在外网简直无法直视。

WebDav呢?其实也有缺点,经过我的测试,在上传大文件(10G以上),在传输到99%时,会卡顿一会儿,大概率是因为上传文件是分块进行的,所有的块上传结束后再整合在一起。SMB就没有这个现象。

最后说说我个人的建议:

局域网环境: 大文件多的直接选择SMB,小文件多的两者都可;视频观看则两者都可;

外网环境: 文件传输两者都可;视频观看直接选择WebDav。

说人话就是,建议SMB和WebDav同时用。SMB负责局域网的文件传输,WebDav外网使用(因为外网受限于带宽,基本不会有很大的文件传输,小文件也能胜任,观看视频什么的更是它的强项)。

写这篇文章的时候头还是有点晕的,如果哪里有问题,欢迎各位领导指正,还是不行的话参考下面的文章,与自己的配置再核对核对。

文章中的配置我测试了一个早上,各个文件都试过,目前拷贝50G的文件也是没问题的。不排除我写文章的时候稀里糊涂的有遗漏的。

参考资料:

software:nginx:webdav [Net Lab]

docker-nginx-webdav-nononsense/nginx.conf at main · dgraziotin/docker-nginx-webdav-nononsense · GitHub

0 0 投票数
文章评分
订阅评论
提醒
guest
0 评论
最旧
最新 最多投票
内联反馈
查看所有评论
滚动至顶部
0
希望看到您的想法,请您发表评论x