前言
继前两篇文章,介绍了两种搭建WebDav的方法:
-
Apache2后端,Nginx反向代理
-
Nginx直接搭建WebDav
这两种方法都存在一个很大的问题,Windows磁盘映射会出现各种错误,而且还不是单一的错误,这两天操碎了心,国内国外文章全部扒了一遍又一遍,所幸最终还是可以解决的。
问题:
-
无法创建、上传文件(夹)
-
提示:目录内已经存在相同的文件,是否覆盖
-
遗留一个
0KB
的空白文件 -
另一个程序已经锁定文件的一部分,无法访问
问题的核心是 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.conf
的http
模块中添加一些配置参数:
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的文件也是没问题的。不排除我写文章的时候稀里糊涂的有遗漏的。
参考资料: