[WebDav] WebDav基础知识

文章目录

  • 什么是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);//初始化curlcurl_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 BodyTiXmlDocument* 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.hqwc.cn/news/484240.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【代码随想录算法训练营Day24】● 回溯法理论基础 ● 77. 组合

文章目录 Day 24 第七章 回溯算法part01理论基础什么是回溯使用原因 & 解决的问题如何理解回溯法 77. 组合思路剪枝代码 Day 24 第七章 回溯算法part01 今日内容&#xff1a; ● 理论基础● 77. 组合 理论基础 其实在讲解二叉树的时候&#xff0c;就给大家介绍过回溯&am…

win系统下安装php8.3版本并配置环境变量的详细教程

本篇文章主要讲解在win系统下安装和配置php8.3版本&#xff0c;并配置环境变量的详细教程。 日期&#xff1a;2024年2月22日 作者&#xff1a;任聪聪 一、下载php8.3版本包 php8.3版本官方下载地址&#xff1a;https://windows.php.net/download#php-8.3 步骤一、打开下载地址…

【鸿蒙 HarmonyOS 4.0】网络请求

一、介绍 资料来自官网&#xff1a;文档中心 网络管理模块主要提供以下功能&#xff1a; HTTP数据请求&#xff1a;通过HTTP发起一个数据请求。WebSocket连接&#xff1a;使用WebSocket建立服务器与客户端的双向连接。Socket连接&#xff1a;通过Socket进行数据传输。 日常…

OceanBase数据迁移-从MySQL导入数据到OceanBase

把MySQL中的数据导入到OceanBase&#xff0c;分几个步骤&#xff1a; 1.准备一份MySQL测试数据集2.使用mydumper工具导出MySQL数据3.使用myloader工具导入到OceanBase4.验证测试数据集在OceanBase下的执行情况 1.准备一份MySQL测试数据集 1.1.从github下载mysql测试数据集&a…

【PX4SimulinkGazebo联合仿真】在Simulink中使用ROS2控制无人机沿自定义圆形轨迹正向飞行(带偏航角控制)并在Gazebo中可视化

在Simulink中使用ROS2控制无人机沿自定义圆形轨迹正向飞行&#xff08;带偏航角控制&#xff09;并在Gazebo中可视化 系统架构Matlab官方例程Control a Simulated UAV Using ROS 2 and PX4 Bridge运行所需的环境配置PX4&Simulink&Gazebo联合仿真实现方法建立Simulink模…

模板(类模板)---C++

模板目录 2.类模板2.1 类模板语法2.2 类模板与函数模板区别2.3 类模板中成员函数创建时机2.4 类模板对象做函数参数2.5 类模板与继承2.6 类模板成员函数类外实现2.7 类模板分文件编写2.8 类模板与友元2.9 类模板案例 2.类模板 2.1 类模板语法 类模板作用&#xff1a; 建立一个…

[嵌入式AI从0开始到入土]15_orangepi_aipro欢迎界面、ATC bug修复、镜像导出备份

[嵌入式AI从0开始到入土]嵌入式AI系列教程 注&#xff1a;等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间&#xff0c;后期会考虑出视频教程&#xff0c;务必催更&#xff0c;以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官…

notepad++运行python闪一下就没啦

问题&#xff1a;Notepad直接快捷键运行Python代码,出现闪一下就没了 解决措施&#xff1a; ①点击菜单运行(Run) --> 运行(Run)弹出的对话框 ②把 cmd /k python "$(FULL_CURRENT_PATH)" & ECHO. & PAUSE & EXIT 粘贴进入这个对话框内 ③点击保存&a…

Rust Vs Go:从头构建一个web服务

Go 和 Rust 之间的许多比较都强调它们在语法和初始学习曲线上的差异。然而&#xff0c;最终的决定性因素是重要项目的易用性。 “Rust 与 Go”争论 Rust vs Go 是一个不断出现的话题&#xff0c;并且已经有很多关于它的文章。部分原因是开发人员正在寻找信息来帮助他们决定下…

EventStream获得数据流,前端配置获得推送的流

如上图所示&#xff0c;请求一个接口&#xff0c;接口以数据流的方式向客户端推送数据&#xff0c;默认需要消息收集一条&#xff0c;在原来的基础上追加&#xff0c;在create-react-app生成的工程中&#xff0c;如果代理使用了中间件http-proxy-middleware&#xff0c;同时dev…

强化学习(GPS)

GPS——Guided Policy Search引导策略搜索 基于模型的强化学习算法 GPS目前被作为基础算法广泛应用于各种强化学习任务中&#xff0c;其出发点在于纯粹的策略梯度方法在更新参数时不会用到环境模型因而属于一种无模型强化学习算法。由于没有利用任何环境的内在属性&#xff0…

stm32cubemx简单介绍

&#xff08;本文为简单介绍&#xff0c;内容源于网络&#xff09; STM32CubeMX是STMicroelectronics推出的一款用于STM32微控制器系列的图形化配置工具&#xff0c;旨在简化嵌入式软件开发过程。本文将对STM32CubeMX进行简要介绍&#xff0c;包括其功能特点、优势以及在嵌入式…