[WebDav] WebDav基础知识

news2024/10/6 10:27:37

文章目录

  • 什么是WebDav
  • WebDav常用命令
  • WebDav常用命令的测试(代码)
    • PROPFIND 方法测试
    • PUT 方法测试
    • GET 方法测试
    • PROPPATCH方法
  • WebDav缓存
    • Cache-Control
    • Etag
      • 测试
    • 强制重新验证
    • 不需要缓存
  • WebDav的锁
  • WebDav的状态码
  • WebDav身份验证
  • WebDav版本控制
  • WebDav和FTP的区别
  • 参考

什么是WebDav

What is WebDAV?
Briefly: WebDAV stands for “Web-based Distributed Authoring and Versioning”. It is a set of extensions to the HTTP protocol which allows users to collaboratively edit and manage files on remote web servers.
WebDAV Resources

WebDav是基于HTTP的协议,他可以允许客户端远程编辑Web内容。

WebDAV的特性和优势
支持创建、修改、复制、移动、移除、查询、列举文件
文件锁
版本控制
支持修改文件属性
安全完善的身份验证机制
支持https加密
支持proxy
客户端缓存
方便的客户端工具:和局域网中的文件共享一样简单使用。
来源:学习WebDav

WebDav常用命令

WebDav在HTTP的基础上扩展了自己的命令,例如:
PROPFIND 用于获取文件夹列表、文件夹内的文件列表、文件夹和文件的属性;
MKCOL 用于创建空文件夹;
PUT 用于上传文件;
GET 用于下载文件;
COPY 用于复制文件;
MOVE 用于移动文件;

WebDav常用命令的测试(代码)

我在坚果云网盘中,创建了几个文件夹,上传了几个文件。并按照如何在Zotero中设置webdav连接到坚果云?进行了网盘的WebDav服务配置,生成了WebDav密码。
在这里插入图片描述
根据学习WebDav ,直接在windows cmd使用curl命令就可以一定程度测试WebDav,我这里是在VS 2022中,通过libcurl库,向坚果云发送请求。
关于VS中如何导入libcurl库,可以看[libcurl] windows visual studio 导入libcurl库。

PROPFIND 方法测试

代码:

#include <curl/curl.h>
#include <iostream>
#include <fstream>

using std::cout;
using std::endl;
using std::ios;

#define ERROR(X) (cout << __FUNCDNAME__ <<  " " << (X) << " " << "error" << endl, -1)
#define ERROR2(X,Y) (cout << __FUNCDNAME__ <<  " " << (X) << " " << (Y) << " " << "error" << endl, -1)

#if 1 // WebDav
size_t write_callback(char* ptr, size_t size, size_t nmemb, void* userdata);
int My_PROPFIND();
FILE* fp;

int main()
{
	//打开一个文件,用于输出WebDav响应
	char filename[256];
	sprintf_s(filename, 256, "%s.%s", "WebDav-Test", "xml");
	errno_t err = fopen_s(&fp, filename, "wb");
	if (err)
		return ERROR2("fopen_s", err);

	//初始化curl
	curl_global_init(CURL_GLOBAL_WIN32);

	//WebDav请求函数
	My_PROPFIND();

	curl_global_cleanup();
	cout << "program end." << endl;
}

int My_PROPFIND()
{
	const char* host = "https://dav.jianguoyun.com";
	const char* url = "https://dav.jianguoyun.com/dav/box1";
	
	CURL* curl = curl_easy_init();
	if (curl) {
		//设置HTTP头		
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPFIND"); //修改HTTP方法
		curl_easy_setopt(curl, CURLOPT_URL, url); //设置URL		
		curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_1_1); //指定HTTP版本
		curl_easy_setopt(curl, CURLOPT_USERNAME, "这里隐藏掉邮箱地址@qq.com"); //设置访问WebDav账号和密码
		curl_easy_setopt(curl, CURLOPT_PASSWORD, "axs5pyhc2j6n7q");
		struct curl_slist* list = NULL; //设置HTTP头部字段
		list = curl_slist_append(list, "Connection: close"); //不要长连接
		list = curl_slist_append(list, "Accept: */*");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
		

		//指定用于SSL证书验证的证书
		CURLcode err = curl_easy_setopt(curl, CURLOPT_CAINFO, "D:\\SourceCode\\cert\\_.jianguoyun.com.crt");
		if (err != CURLE_OK) {
			cout << "CURLOPT_CAPATH err:" << err << endl;
		}
		//如果不设置,会出现:unable to get local issuer certificate的错误

		//设定HTTP响应的处理方法
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)fp);
		//设定控制台回显调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		//执行HTTP请求
		CURLcode ret = curl_easy_perform(curl);
		if (ret != CURLE_OK) {
			curl_easy_cleanup(curl);
			fclose(fp);
			return ERROR2("curl_easy_perform", ret);
		}
	}
	else {
		fclose(fp);
		return ERROR("curl_easy_init");
	}
	fclose(fp);
	curl_easy_cleanup(curl);
	return 0;
}

size_t write_callback(char* ptr, size_t size, size_t nmemb, void* userdata)
{
	int realsize = size * nmemb;
	fwrite(ptr, 1, realsize, fp);
	return realsize;
}
#endif

控制台输出:

* Host dav.jianguoyun.com:443 was resolved.
* IPv6: (none)
* IPv4: 36.155.116.36, 36.155.116.35
*   Trying 36.155.116.36:443...
* Connected to dav.jianguoyun.com (36.155.116.36) port 443
* ALPN: curl offers http/1.1
*  CAfile: D:\SourceCode\cert\_.jianguoyun.com.crt
*  CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 / [blank] / UNDEF
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=*.jianguoyun.com
*  start date: Jan 23 00:00:00 2024 GMT
*  expire date: Feb 19 23:59:59 2025 GMT
*  subjectAltName: host "dav.jianguoyun.com" matched cert's "*.jianguoyun.com"
*  issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA
*  SSL certificate verify ok.
*   Certificate level 0: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* using HTTP/1.x
* Server auth using Basic with user ‘这里隐藏掉邮箱地址@qq.com'
> PROPFIND /dav/box1 HTTP/1.1
Host: dav.jianguoyun.com
Authorization: Basic MjgwMjAzNzEyN这里隐藏掉B5aGMyajZuN3F0eg==
Connection: close
Accept: */*

< HTTP/1.1 207 Multi-Status
< Server: nginx
< Date: Mon, 19 Feb 2024 04:14:58 GMT
< Content-Type: text/xml; charset=UTF-8
< Content-Length: 2882
< Connection: close
< Pragma: no-cache
< Cache-Control: no-cache
<
* Closing connection
program end.

可以看到,发出的请求是:

> PROPFIND /dav/box1 HTTP/1.1
Host: dav.jianguoyun.com
Authorization: Basic MjgwMjAzNzEyN这里隐藏掉B5aGMyajZuN3F0eg==
Connection: close
Accept: */*

收到的响应HTTP头是:

< HTTP/1.1 207 Multi-Status
< Server: nginx
< Date: Mon, 19 Feb 2024 04:14:58 GMT
< Content-Type: text/xml; charset=UTF-8
< Content-Length: 2882
< Connection: close
< Pragma: no-cache
< Cache-Control: no-cache

输出到文件中的XML内容是:

<d:multistatus>
<d:response>
 <d:href>/dav/box1/</d:href>
<d:propstat>
<d:prop>
 <d:getcontenttype>httpd/unix-directory</d:getcontenttype>
 <d:displayname>box1</d:displayname>
 <d:owner>这里隐藏掉邮箱地址@qq.com</d:owner>
<d:resourcetype>
 <d:collection/>
 </d:resourcetype>
 <d:getcontentlength>0</d:getcontentlength>
 <d:getlastmodified>Mon, 19 Feb 2024 04:14:58 GMT</d:getlastmodified>
<d:current-user-privilege-set>
<d:privilege>
 <d:read/>
 </d:privilege>
<d:privilege>
 <d:write/>
 </d:privilege>
<d:privilege>
 <d:all/>
 </d:privilege>
<d:privilege>
 <d:read_acl/>
 </d:privilege>
<d:privilege>
 <d:write_acl/>
 </d:privilege>
 </d:current-user-privilege-set>
 </d:prop>
 <d:status>HTTP/1.1 200 OK</d:status>
 </d:propstat>
 </d:response>
<d:response>
 <d:href>/dav/box1/WeatherWS.xml</d:href>
<d:propstat>
<d:prop>
 <d:getetag>UsZ7ybf73r39UXEEPQs5qA</d:getetag>
 <d:getcontenttype>text/xml</d:getcontenttype>
 <d:displayname>WeatherWS.xml</d:displayname>
 <d:owner>这里隐藏掉邮箱地址@qq.com</d:owner>
 <d:getcontentlength>29712</d:getcontentlength>
 <d:getlastmodified>Fri, 29 Dec 2023 09:02:10 GMT</d:getlastmodified>
 <d:resourcetype/>
<d:current-user-privilege-set>
<d:privilege>
 <d:read/>
 </d:privilege>
<d:privilege>
 <d:write/>
 </d:privilege>
<d:privilege>
 <d:all/>
 </d:privilege>
<d:privilege>
 <d:read_acl/>
 </d:privilege>
<d:privilege>
 <d:write_acl/>
 </d:privilege>
 </d:current-user-privilege-set>
 </d:prop>
 <d:status>HTTP/1.1 200 OK</d:status>
 </d:propstat>
 </d:response>
<d:response>
 <d:href>/dav/box1/box1_1</d:href>
<d:propstat>
<d:prop>
 <d:getetag/>
 <d:getcontenttype>httpd/unix-directory</d:getcontenttype>
 <d:displayname>box1_1</d:displayname>
 <d:owner>这里隐藏掉邮箱地址@qq.com</d:owner>
 <d:getcontentlength>0</d:getcontentlength>
 <d:getlastmodified>Tue, 13 Feb 2024 04:29:51 GMT</d:getlastmodified>
<d:resourcetype>
 <d:collection/>
 </d:resourcetype>
<d:current-user-privilege-set>
<d:privilege>
 <d:read/>
 </d:privilege>
<d:privilege>
 <d:write/>
 </d:privilege>
<d:privilege>
 <d:all/>
 </d:privilege>
<d:privilege>
 <d:read_acl/>
 </d:privilege>
<d:privilege>
 <d:write_acl/>
 </d:privilege>
 </d:current-user-privilege-set>
 </d:prop>
 <d:status>HTTP/1.1 200 OK</d:status>
 </d:propstat>
 </d:response>
<d:response>
 <d:href>/dav/box1/box1file.pdf</d:href>
<d:propstat>
<d:prop>
 <d:getetag>rlLyz4SUXar-UNmip-F5Qw</d:getetag>
 <d:getcontenttype>application/pdf</d:getcontenttype>
 <d:displayname>box1file.pdf</d:displayname>
 <d:owner>这里隐藏掉邮箱地址@qq.com</d:owner>
 <d:getcontentlength>2422816</d:getcontentlength>
 <d:getlastmodified>Wed, 15 Nov 2023 08:43:08 GMT</d:getlastmodified>
 <d:resourcetype/>
<d:current-user-privilege-set>
<d:privilege>
 <d:read/>
 </d:privilege>
<d:privilege>
 <d:write/>
 </d:privilege>
<d:privilege>
 <d:all/>
 </d:privilege>
<d:privilege>
 <d:read_acl/>
 </d:privilege>
<d:privilege>
 <d:write_acl/>
 </d:privilege>
 </d:current-user-privilege-set>
 </d:prop>
 <d:status>HTTP/1.1 200 OK</d:status>
 </d:propstat>
 </d:response>
 </d:multistatus>

我对Dav中的box1文件夹发送了PROPDIND请求,在响应回来的XML内容中,列出了box1中的每个文件夹和文件(包括box1自己)。每个<d:response>节点都包含了一个文件夹或者文件,<d:response>节点,是文件夹或者文件的属性信息。

PUT 方法测试

只保留方法部分,其余代码省略。

int My_PUT()
{
	//这里需要指明需要在Dav上创建的文件的路径“box1”和名字“Upload_test.txt”
	const char* url = "https://dav.jianguoyun.com/dav/box1/Upload_test.txt";
	CURL* curl = curl_easy_init();
	if (curl) {		
		//设置HTTP头		
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); //修改HTTP方法
		curl_easy_setopt(curl, CURLOPT_URL, url); //设置URL		
		curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_1_1); //指定HTTP版本
		curl_easy_setopt(curl, CURLOPT_USERNAME, "2xxxxxxxx4@qq.com"); //设置访问WebDav账号和密码
		curl_easy_setopt(curl, CURLOPT_PASSWORD, "axs5pyhc2j6n7q");
		struct curl_slist* list = NULL; //设置HTTP头部字段
		list = curl_slist_append(list, "Connection: close"); //不要长连接
		list = curl_slist_append(list, "Accept: */*");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);

		//设置要上传的文件信息
		//打开文件
		curl_off_t fsize = 0;
		FILE* src = nullptr;
		errno_t ferr = fopen_s(&src, "D:\\SourceCode\\TransFILE1.txt", "rb");
		if (ferr)
			return -1;
		//获取文件大小
		fseek(src, 0, SEEK_END);	
		fsize = ftell(src);
		fseek(src, 0, SEEK_SET);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb); //设置读取文件的回调函数
		curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); //启动Upload服务
		curl_easy_setopt(curl, CURLOPT_READDATA, src);//设置传入回调函数的文件句柄
		curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize);//设置文件大小

		//指定用于SSL证书验证的证书
		CURLcode err = curl_easy_setopt(curl, CURLOPT_CAINFO, "D:\\SourceCode\\cert\\_.jianguoyun.com.crt");
		if (err != CURLE_OK) {
			cout << "CURLOPT_CAPATH err:" << err << endl;
		}
		//如果不设置,会出现:unable to get local issuer certificate的错误

		//设定HTTP响应的处理方法
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)fp);
		//设定控制台回显调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		//执行HTTP请求
		CURLcode ret = curl_easy_perform(curl);
		if (ret != CURLE_OK) {
			curl_easy_cleanup(curl);
			fclose(fp);
			return ERROR2("curl_easy_perform", ret);
		}
	}
	else {
		fclose(fp);
		return ERROR("curl_easy_init");
	}
	fclose(fp);
	curl_easy_cleanup(curl);
	return 0;
}
static size_t read_cb(char* ptr, size_t size, size_t nmemb, void* userdata)
{
	FILE* src = (FILE*)userdata;
	/* copy as much data as possible into the 'ptr' buffer, but no more than
	   'size' * 'nmemb' bytes */
	size_t retcode = fread(ptr, size, nmemb, src);

	return retcode;
}

控制台回显信息(部分):

> PUT /dav/box1/Upload_test.txt HTTP/1.1
Host: dav.jianguoyun.com
Authorization: Basic MjgwMjAzNzEyNEB---------------aGMyajZuN3F0eg==
Connection: close
Accept: */*
Content-Length: 1844

* We are completely uploaded and fine
< HTTP/1.1 204 No Content
< Server: nginx
< Date: Mon, 19 Feb 2024 05:59:17 GMT
< Connection: close
< X-File-Version: 3
< Pragma: no-cache
< Cache-Control: no-cache
<
* Closing connection

WebDav查看:
在这里插入图片描述

GET 方法测试

int My_GET()
{
	const char* url = "https://dav.jianguoyun.com/dav/box1/Upload_test.txt";

	CURL* curl = curl_easy_init();
	if (curl) {
		//设置HTTP头		
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); //修改HTTP方法
		curl_easy_setopt(curl, CURLOPT_URL, url); //设置URL		
		curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_1_1); //指定HTTP版本
		curl_easy_setopt(curl, CURLOPT_USERNAME, "2--------4@qq.com"); //设置访问WebDav账号和密码
		curl_easy_setopt(curl, CURLOPT_PASSWORD, "axs5pyhc2j6n7q");
		struct curl_slist* list = NULL; //设置HTTP头部字段
		list = curl_slist_append(list, "Connection: close"); //不要长连接
		list = curl_slist_append(list, "Accept: */*");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);

		//指定用于SSL证书验证的证书
		CURLcode err = curl_easy_setopt(curl, CURLOPT_CAINFO, "D:\\SourceCode\\cert\\_.jianguoyun.com.crt");
		if (err != CURLE_OK) {
			cout << "CURLOPT_CAPATH err:" << err << endl;
		}
		//如果不设置,会出现:unable to get local issuer certificate的错误

		//设定HTTP响应的处理方法
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)fp);
		//设定控制台回显调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		//执行HTTP请求
		CURLcode ret = curl_easy_perform(curl);
		if (ret != CURLE_OK) {
			curl_easy_cleanup(curl);
			fclose(fp);
			return ERROR2("curl_easy_perform", ret);
		}
	}
	else {
		fclose(fp);
		return ERROR("curl_easy_init");
	}
	fclose(fp);
	curl_easy_cleanup(curl);
	return 0;
}

控制台回显结果(部分):

> GET /dav/box1/Upload_test.txt HTTP/1.1
Host: dav.jianguoyun.com
Authorization: Basic MjgwMjAzNzEyNEBxc--------------GMyajZuN3F0eg==
Connection: close
Accept: */*

< HTTP/1.1 200 OK
< Server: nginx
< Date: Mon, 19 Feb 2024 06:13:18 GMT
< Content-Type: text/plain
< Content-Length: 1844
< Connection: close
< Etag: 8sKBsnMc5tH71U67xjQTCQ
< Pragma: public
< Cache-Control: max-age=5
< Content-Disposition: attachment
<
* Closing connection
program end.

下载的文件内容保存在以下代码绑定的文件中了:

		//设定HTTP响应的处理方法
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)fp);

PROPPATCH方法

PROPPATCH方法用于修改文件的属性。
WebDav方法的HTTP Body是XML格式,前面尝试的几个请求都没有添加Body。
PROPPATCH需要在Body中添加需要修改的属性指令。

以刚才PUT的文件Upload_test.txt为目标,把它的<d:displayname>修改为Upload_test_1.txt。
但是没有效果,坚果云给的响应中消息中,也没有显示失败信息。

我咨询了坚果云的客服,客服联系技术给出了回复,目前坚果云不支持PROPPATCH方法
因此,无法验证我的代码是否正确,但是还是记录一下代码,期待以后有机会验证。

代码:

int My_PROPPATCH()
{
	const char* url = "https://dav.jianguoyun.com/dav/box1/Upload_test.txt";

	CURL* curl = curl_easy_init();
	if (curl) {
		//设置HTTP头		
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PROPPATCH"); //修改HTTP方法
		curl_easy_setopt(curl, CURLOPT_URL, url); //设置URL		
		curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_1_1); //指定HTTP版本
		curl_easy_setopt(curl, CURLOPT_USERNAME, "2802037124@qq.com"); //设置访问WebDav账号和密码
		curl_easy_setopt(curl, CURLOPT_PASSWORD, "axs5pyhc2j6n7qtz");
		struct curl_slist* list = NULL; //设置HTTP头部字段
		//list = curl_slist_append(list, "Connection: close"); //不要长连接
		list = curl_slist_append(list, "Accept: */*");
		list = curl_slist_append(list, "Content-Type:application/xml; charset= 'utf-8'");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);

		//指定用于SSL证书验证的证书
		CURLcode err = curl_easy_setopt(curl, CURLOPT_CAINFO, "D:\\SourceCode\\cert\\_.jianguoyun.com.crt");
		if (err != CURLE_OK) {
			cout << "CURLOPT_CAPATH err:" << err << endl;
		}
		//如果不设置,会出现:unable to get local issuer certificate的错误

		//设定HTTP响应的处理方法
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)fp);
		//设定控制台回显调试信息
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		//使用TinyXML库,添加Http Body
		TiXmlDocument* tinyXmlDoc = new TiXmlDocument();

		TiXmlDeclaration* tinyXmlDeclare = new TiXmlDeclaration("1.0", "utf-8", "");  // xml的声明
		tinyXmlDoc->LinkEndChild(tinyXmlDeclare);

		TiXmlElement* Library = new TiXmlElement("D:propertyupdate");
		Library->SetAttribute(" xmlns:D", "DAV");
		Library->SetAttribute(" xmlns:S", "http://ns.jianguoyun.com");
		tinyXmlDoc->LinkEndChild(Library);	

		TiXmlElement* Set = new TiXmlElement("D:set");
		Library->LinkEndChild(Set);

		TiXmlElement* Prop = new TiXmlElement("D:prop");
		Set->LinkEndChild(Prop);

		TiXmlElement* Displayname2 = new TiXmlElement("S:publish");
		TiXmlText* newname = new TiXmlText("Upload_test_1.txt");	
		Displayname2->LinkEndChild(newname);	
		Prop->LinkEndChild(Displayname2);

		TiXmlPrinter printer;
		tinyXmlDoc->Accept(&printer);
		printf("%s\n", printer.CStr());
		char body[1024] = { 0x00 };
		strcpy_s(body, (rsize_t)1024, printer.CStr());
		curl_off_t size = strlen(body);
		
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb_patch); //设置读取文件的回调函数
		curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); //启动Upload服务
		curl_easy_setopt(curl, CURLOPT_READDATA, body);//设置传入回调函数的文件句柄
		curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)size);//设置文件大小

		//执行HTTP请求
		CURLcode ret = curl_easy_perform(curl);
		if (ret != CURLE_OK) {
			curl_easy_cleanup(curl);
			/*fclose(fp);*/
			return ERROR2("curl_easy_perform", ret);
		}
	}
	else {
		//fclose(fp);
		return ERROR("curl_easy_init");
	}
	//fclose(fp);
	curl_easy_cleanup(curl);
	return 0;
}

控制台回显:

> PROPPATCH /dav/box1/Upload_test.txt HTTP/1.1
Host: dav.jianguoyun.com
Authorization: Basic MjgwMjAzNzEyNEBxcS5jb206YXhzNXB5aGMyajZuN3F0eg==
Accept: */*
Content-Type:application/xml; charset= 'utf-8'
Content-Length: 243

* We are completely uploaded and fine
< HTTP/1.1 207 Multi-Status
< Server: nginx
< Date: Mon, 19 Feb 2024 09:23:56 GMT
< Content-Type: text/xml; charset=UTF-8
< Content-Length: 524
< Connection: keep-alive
< Keep-Alive: timeout=60
< Pragma: no-cache
< Cache-Control: no-cache

Response的正文:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://ns.jianguoyun.com">
<d:response>
<d:href>/dav/box1/Upload_test.txt</d:href>
<d:propstat>
<d:prop>
<m:Win32LastModifiedTime xmlns:m="urn:schemas-microsoft-com:"/>
<m:Win32FileAttributes xmlns:m="urn:schemas-microsoft-com:"/>
<m:Win32CreationTime xmlns:m="urn:schemas-microsoft-com:"/>
<m:Win32LastAccessTime xmlns:m="urn:schemas-microsoft-com:"/>
</d:prop><d:status>HTTP/1.1 200 OK</d:status>
</d:propstat></d:response></d:multistatus>

WebDav缓存

在上面的PROPFIND等请求的响应头中,能看到以下字段:

< Etag: 8sKBsnMc5tH71U67xjQTCQ
< Cache-Control: max-age=5

Cache-Control

Cache-Control: max-age=5 就是控制缓存的过期时间,这里是5秒后缓存过期。

Cache-Control也可以用来设置缓存类型,Cache-Control: private //私有缓存
Cache-Control: public //贡献缓存。

Etag

他们是用于HTTP缓存控制的字段。

Etag响应头,是HTTP中资源的特定版本标识符。
Etag相当于资源的指纹, URL 中的资源更改了,就一定要生成新的 ETag 值。
Etag由服务器生成,在客户端请求资源时通过Etag响应头发给客户端。

客户端下次请求同一个资源时,如果资源已经过期,客户端请求通过If-None-Match请求头,把Etag的值发给服务器,服务器可以通过If-None-Match的值,判断资源是否已经改变(这个过程叫做重新验证)。如果客户端的If-None-Match和服务器资源当前的Etag一致,服务器就不需要发送完整数据了,返回一个 304 Not Modified 状态即可。

测试

首先我用PROPFIND获取了WebDav中,一个文件的属性,它的Etag是:

<d:getetag>uLR1Dl0O-2f8uVxiMCSTGQ</d:getetag>

我在GET方法的请求头中,添加了If-None_Match字段,值就是刚才获取的文件Etag。

list = curl_slist_append(list, "If-None-Match: uLR1Dl0O-2f8uVxiMCSTGQ");

发送GET方法请求后,服务器返回304 Not Modified,即文件没有变动,无需重新获取数据。
在这里插入图片描述

强制重新验证

如果服务器想要客户端在资源没有过期的时候,也要获取最新的资源。
可以在 存在Etag或者Last-Modified头的同时,指定Cache-Control: no-cache或Cache-Control: max-age=0, must-revalidate

不需要缓存

指定Cache-Control: no-cache

GET、HEAD、OPTIONS 方法是幂等的,不会改变服务器资源的状态,是可以缓存的。
其余的方法是不建议缓存,或者不可以缓存的。

完整的缓存控制可以参考:【HTTP完全注解】看了还搞不懂缓存你直接来打我

WebDav的锁

WebDav 规范中存在排他锁、共享锁。
WebDav规范中只规定了写入锁(Write),不同的服务器可能实现了不同类型的锁。
在不同的服务器中,可能不支持锁,或者支持一种锁,或者支持多种锁。

WebDav中的每一个锁都会生成一个锁令牌(lock token),在对被锁住的对象进行操作室,HTTP头必须提交锁令牌信息。

有LOCK和UNLOCK方法来进行枷锁和解锁。

WebDav的状态码

WebDav扩展了以下状态码:
207:多状态,查看响应正文来获取详细状态。
422:请求URL存在,但是请求正文的XML内容不正确
423:请求的文件对象已被锁定
424:依赖失败,比如PROPPATCH中的一个属性修改命令失败,其余的命令也会失败。
507:服务器暂时无法提供存储空间

WebDav身份验证

通过TLS确保Basic验证信息安全。

WebDav版本控制

TODO.
参考:Versioning Extensions to WebDAV

WebDav和FTP的区别

WebDav提供了缓存功能,FTP没有;
WebDav一般通过HTTPS的443端口通信,FTP需要用20和21端口通信。
WebDav提供了锁,FTP没有。

参考

WebDAV Resources
WebDAV 规范文档
WebDAV 规范文档-Gitee
学习WebDav
如何在Zotero中设置webdav连接到坚果云?
【HTTP完全注解】看了还搞不懂缓存你直接来打我
http 三种认证方式 Basic Session Token 简介
Versioning Extensions to WebDAV

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1462940.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mplfinance 使用make_addplot做复杂股票走势图

mplfinance 使用make_addplot做复杂股票走势图 1.代码 import talib as tb import pandas as pd import mplfinance as mpfimport matplotlib.pyplot as pltplt.rcParams[font.sans-serif][simHei] # 以黑体显示中文 plt.rcParams[axes.unicode_minus]False # 解决保存图像符…

通俗易懂分析:Vite和Webpack的区别

1、对项目构建的理解 先从浏览器出发&#xff0c; 浏览器是由浏览器内核和JS引擎组成&#xff1b;浏览器内核编译解析html代码和css代码&#xff0c;js引擎编译解析JavaScript代码&#xff1b;所以从本质上&#xff0c;浏览器只能识别运行JavaScript、CSS、HTML代码。 而我们在…

基于CNN-GRU-Attention的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 CNN&#xff08;卷积神经网络&#xff09;部分 4.2 GRU&#xff08;门控循环单元&#xff09;部分 4.3 Attention机制部分 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版…

STM32基于寄存器编程

在51中让一个引脚输出高低电平只需要一个步骤&#xff0c;而在32中至少需要三个步骤。 开启对应GPIO的时钟配置对应IO口设置IO口 本文将一步步进阶的讲解&#xff0c;三种寄存器编程的方法。 使用地址赋值进行配置使用ST的宏进行配置只控制需要的位&#xff08;位运算&#…

无/自监督去噪(2)——Noise2Noise (N2N) 理论分析(从损失函数入手)

目录 读前须知1. 前置知识——L1和L2 loss的特性2. additive Gaussian noise (spatial independent noise), L 2 L_2 L2​首杀3. brown Gaussian noise (spatial dependent noise), L 2 L_2 L2​双杀4. blind text removal, L 2 L_2 L2​导致结果偏灰, L 1 L_1 L1​前来破局…

刚开的抖店怎样推广?找主播带货,积累资源/渠道,拉动自然流量成交

我是王路飞。 2024年&#xff0c;依旧有很多人想入局抖音小店。 刚复工没几天&#xff0c;我就已经收到好多粉丝朋友的私信了&#xff0c;纷纷表示自己已经开通了抖店了&#xff0c;但是不会运营&#xff0c;现在新店应该怎样进行推广呢&#xff1f; 这篇内容就给你们详细说…

交换瓶子【第七届】【省赛】【A组】

题目描述 有N个瓶子&#xff0c;编号 1 ~ N&#xff0c;放在架子上。 比如有5个瓶子&#xff1a; 2 1 3 5 4 要求每次拿起2个瓶子&#xff0c;交换它们的位置。 经过若干次后&#xff0c;使得瓶子的序号为&#xff1a; 1 2 3 4 5 对于这么简单的情况&#xff0c;显然&#…

stm32——hal库学习笔记(DAC)

这里写目录标题 一、DAC简介&#xff08;了解&#xff09;1.1&#xff0c;什么是DAC&#xff1f;1.2&#xff0c;DAC的特性参数1.3&#xff0c;STM32各系列DAC的主要特性 二、DAC工作原理&#xff08;掌握&#xff09;2.1&#xff0c;DAC框图简介&#xff08;F1&#xff09;2.2…

用结构减法比较平面上4点结构的顺序

( A, B )---6*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有6个节点&#xff0c;AB训练集各由6张二值化的图片组成&#xff0c;A有4个点&#xff0c;B全是0.收敛误差7e-4&#xff0c;收敛199次&#xff0c;统计迭代次数平均值并排序。 如果行和列自由变换&#xff0c;迭代次数不…

英伟达推出免训练,可生成连贯图片的文生图模型

目前&#xff0c;多数文生图模型皆使用的是随机采样模式&#xff0c;使得每次生成的图像效果皆不同&#xff0c;在生成连贯的图像方面非常差。 例如&#xff0c;想通过AI生成一套图像连环画&#xff0c;即便使用同类的提示词也很难实现。虽然DALLE 3和Midjourney可以对图像实现…

【UI自动化】使用poco框架进行元素唯一定位

直接选择&#xff1a; 1.poco(text买入).click() 2.poco("android.widget.ImageView").click()相对选择、空间选择&#xff1a; 3.poco(text/name).parent().child()[0].click()正则表达式&#xff1a; 4.listpoco(textMatches".*ETF")今天主要想记录下…

门控时钟基础知识

什么是门控时钟 RTL中的门控时钟 通常情况下&#xff0c;时钟树由大量的缓冲器和反相器组成&#xff0c;时钟信号为设计中翻转率最高的信号&#xff0c;时钟树的功耗可能高达整个设计功耗40%。 加入门控时钟电路后&#xff0c;由于减少了时钟树的翻转&#xff0c;节省了翻转功…

windows下采用 nginx配置websocket支持wss流程

第一步、安装OpenSSL &#xff08;1&#xff09;下载OpenSSL软件包 地址&#xff1a;https://slproweb.com/products/Win32OpenSSL.html OpenSSL版本说明&#xff1a; Win64 OpenSSL v1.1.1wLight&#xff0c;安装Win64 OpenSSL v1.1.1w最常用的软件包 Win64 OpenSSL v1.1…

真实的数据如何获取

数据 在信息过载的互联网信息中挖掘有价值的信息是非常难的。 我自己退一步&#xff0c;要想寻求真实的信息也是非常难的。 那么关于个人博客具体浏览量的真实信息到底如何呢&#xff1f; 请看下图&#xff1a; 真相残酷&#xff0c;现实骨感。 核心 如果要抛开自欺欺人&a…

第二证券:5天骤降14!转融券市场再降温

转融券存量在快速下降。 到2月21日&#xff0c;转融券的存量股数为50.36亿股&#xff0c;近5个交易日内下降超20%。券商两融人士向券商我国记者表明&#xff0c;2月6日&#xff0c;证监会表明暂停转融券新增规划&#xff0c;存量逐渐了断&#xff0c;从目前的数据来看&#xf…

[corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape

前言 题目来源&#xff1a;竞赛官网 – 建议这里下载&#xff0c;文件系统/带符号的 vmlinux 给了 参考 [corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape Exploiting poll_list Objects In The Linux Kernel – 原作者文章&#xff0c;poll_list 利用方式…

7 数据迁移至达梦数据库

无论使用哪种解决方案很大可能性都需要进行数据迁移&#xff0c;即将旧的非 达梦数据库的数据迁移到达梦数据库。 我们要把 Nacos 的数据或者 SQL 语句迁移到达梦数据库。借助 DM 数据迁移工具 &#xff0c;完成 Nacos 配置数据表迁移到达梦数据库。

ros自定义action记录

文章目录 自定义action1. 定义action文件2. 修改 package.xml3. 修改 CMakeLists.txt4. 运行 catkin build5. simple_action_server.py6. simple_action_client.py 测试 自定义action ros 版本&#xff1a;kinetic 自定义test包的文件结构如下 |-- test | |-- CMakeLists.t…

【9-1】实验——Neo4j实战操作

目录 一、Neo4j操作——CQL 1、常用CQL命令 2.常用CQL函数 3.图数据的形式 二、实战代码1.create命令 2. MATCH命令 三、使用neo4j工具导入知识图谱 1、工具&#xff1a;neo4j-admin 2、图谱导入&#xff1a; 3、更新图谱&#xff1a; 一、Neo4j操作——CQL 1、常用…

RMAN备份与恢复

文章目录 一、RMAN介绍二、全量备份三、增量备份0级备份1级增量备份累积性差量备份总结 四、压缩备份压缩备份介绍压缩备份操作压缩备份优缺点 五、异常恢复1、恢复前的准备2、恢复数据库 六、RMAN相关参数 一、RMAN介绍 RMAN&#xff08;Recovery Manager&#xff09;是Oracl…