我正在尝试在 NWebDAV 和 ASP.NET Core 3.1 之上实现自定义 CardDAV 服务器,使用现有数据库作为联系人的实际数据源。 (NWebDAV 似乎对基本的 WebDAV 概念有很好的支持,比如响应
PROPFIND
。开箱即用,运行它的示例项目来为你的主目录提供服务似乎效果很好。OTOH,像 REPORT
这样的东西显然丢失了,我我还不确定这需要多少工作。)
我使用 iOS 13 作为我的主要测试客户端。
我已成功获得:
所以我知道它正在解析我的
PROPFIND
回复到某个点。但后来就什么也没有了。据我了解,它应该向我的服务器发出某种 REPORT
请求,要么首先进行完整同步,要么在搜索字段中输入内容时查询特定联系人。似乎从来没有尝试过。
我给它类似:
<addressbook-home-set xmlns="urn:ietf:params:xml:ns:carddav">
<D:href>/addressbooks/sample/108</D:href>
<D:href>/addressbooks/sample/109</D:href>
</addressbook-home-set>
它会针对每个地址簿发出
PROPFIND
请求,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<A:propfind xmlns:A="DAV:">
<A:prop>
<A:add-member />
<E:bulk-requests xmlns:E="http://me.com/_namespace/" />
<A:current-user-privilege-set />
<A:displayname />
<E:guardian-restricted xmlns:E="http://me.com/_namespace/" />
<D:max-image-size xmlns:D="urn:ietf:params:xml:ns:carddav" />
<D:max-resource-size xmlns:D="urn:ietf:params:xml:ns:carddav" />
<C:me-card xmlns:C="http://calendarserver.org/ns/" />
<A:owner />
<C:push-transports xmlns:C="http://calendarserver.org/ns/" />
<C:pushkey xmlns:C="http://calendarserver.org/ns/" />
<A:quota-available-bytes />
<A:quota-used-bytes />
<A:resource-id />
<A:resourcetype />
<A:supported-report-set />
<A:sync-token />
</A:prop>
</A:propfind>
我对此回应如下:
<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:" xmlns:Z="urn:schemas-microsoft-com:">
<D:response>
<D:href>http://localhost:55946/addressbooks/sample/108</D:href>
<D:propstat>
<D:prop>
<D:add-member />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}add-member is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<bulk-requests xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}bulk-requests is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<guardian-restricted xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}guardian-restricted is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-image-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-image-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-resource-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-resource-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:owner />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}owner is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<push-transports xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}push-transports is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<pushkey xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}pushkey is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-available-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-available-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-used-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-used-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:resource-id />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}resource-id is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:sync-token />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}sync-token is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:current-user-privilege-set>
<D:privilege>
<D:read />
</D:privilege>
<D:privilege>
<D:read-acl />
</D:privilege>
<D:privilege>
<D:read-current-user-privilege-set />
</D:privilege>
<D:privilege>
<D:write />
</D:privilege>
<D:privilege>
<D:bind />
</D:privilege>
</D:current-user-privilege-set>
<D:displayname>SampleContacts108</D:displayname>
<me-card xmlns="http://calendarserver.org/ns/">
<D:href>/addressbooks/sample/108/contact-49191/</D:href>
</me-card>
<D:resourcetype>
<D:collection />
<addressbook xmlns="urn:ietf:params:xml:ns:carddav" />
</D:resourcetype>
<D:supported-report-set>
<D:supported-report>
<addressbook-query xmlns="urn:ietf:params:xml:ns:carddav" />
</D:supported-report>
<D:supported-report>
<addressbook-multiget xmlns="urn:ietf:params:xml:ns:carddav" />
</D:supported-report>
<D:supported-report>
<D:expand-property />
</D:supported-report>
</D:supported-report-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://localhost:55946/addressbooks/sample/108/Bar,Foo</D:href>
<D:propstat>
<D:prop>
<D:add-member />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}add-member is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<bulk-requests xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}bulk-requests is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:current-user-privilege-set />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}current-user-privilege-set is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<guardian-restricted xmlns="http://me.com/_namespace/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://me.com/_namespace/}guardian-restricted is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-image-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-image-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<max-resource-size xmlns="urn:ietf:params:xml:ns:carddav" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {urn:ietf:params:xml:ns:carddav}max-resource-size is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<me-card xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}me-card is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:owner />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}owner is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<push-transports xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}push-transports is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<pushkey xmlns="http://calendarserver.org/ns/" />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {http://calendarserver.org/ns/}pushkey is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-available-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-available-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:quota-used-bytes />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}quota-used-bytes is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:resource-id />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}resource-id is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:resourcetype />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}resourcetype is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:supported-report-set />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}supported-report-set is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:sync-token />
</D:prop>
<D:status>HTTP/1.1 404 Not Found</D:status>
<D:responsedescription>Property {DAV:}sync-token is not supported.</D:responsedescription>
</D:propstat>
<D:propstat>
<D:prop>
<D:displayname>Bar, Foo</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
(我已经实现了
me-card
,因为有人说不这样做可能会使 iOS 联系人崩溃,并希望它会提示 iOS 至少 尝试获取我的卡。但是唉。)
此响应包括地址簿本身的元数据以及其中的示例联系人。我不确定这是否正确,但删除该联系人似乎并没有改变任何事情。
我支持报告
addessbook-query
和addressbook-multiget
。我对8的阅读。规范中的地址簿报告是这应该足以符合标准。
令我困惑的是,什么都没有。没有面向用户的错误,没有进一步的请求等。
我确实在控制台中找到了一些东西:
com.apple.dataaccess debug 10:52:13.523530+0200 dataaccessd <private>: There are no server side items to grab, so I'm outta here
但我不知道这是否指的是this帐户(可能是不同的服务器)。如果确实如此,我很想知道是什么让 iOS 得出这个结论?
所以,我的主要问题是:我的基本假设是否正确,即 CardDAV 客户端最终应该发出
REPORT
请求来查询联系人?
我猜你已经解决了这个问题,或者像不久前一样继续你的生活! CardDAV 确实有点特殊!我还没有发现不实现 me-card 会导致 ios 联系人崩溃。
iOS 和联系人应用程序值得注意的一件令人沮丧的事情是,它会在需要时进行同步,并且下拉刷新不会执行任何操作。
如果您在实现此操作时仍然遇到问题,我建议使用启用了 SSL 的 Charles 代理来监听通信。您可以轻松地将手机连接到它。
要进行调试,您可以在 Contactzilla 注册试用(这是我的产品,请注意),您可以在那里窥探该过程。如果您遇到困难,请随时给我留言。