1.1. API基础知识

CouchDB API是连接到CouchDB实例的主要方法。使用HTTP发出请求,请求用于从数据库请求信息、存储新数据以及对存储在文档中的信息执行视图和格式化。

对API的请求可以根据您正在访问的CouchDB系统的不同区域以及用于发送请求的HTTP方法进行分类。不同的方法意味着不同的操作,例如从数据库检索信息通常由 GET 操作,而更新由 POSTPUT 请求。必须为不同方法提供的信息之间存在一些差异。有关基本HTTP方法和请求结构的指南,请参阅 请求格式和响应 .

对于几乎所有的操作,提交的数据和返回的数据结构都是在JavaScript对象表示法(JSON)对象中定义的。中提供了有关JSON的内容和数据类型的基本信息 JSON基础知识 .

使用标准HTTP状态代码报告访问CouchDB API时的错误。中提供了CouchDB返回的泛型代码的指南 状态代码HTTP .

当访问couchdbapi的特定区域时,将提供关于HTTP方法和请求、JSON结构和错误代码的特定信息和示例。

1.1.1. 请求格式和响应

CouchDB支持以下HTTP请求方法:

  • GET

    请求指定的项。与普通的HTTP请求一样,URL的格式定义了返回的内容。使用CouchDB,可以包括静态项、数据库文档、配置和统计信息。在大多数情况下,信息以JSON文档的形式返回。

  • HEAD

    这个 HEAD 方法来获取 GET 没有响应主体的请求。

  • POST

    上传数据。在CouchDB内 POST 用于设置值,包括上载文档、设置文档值和启动某些管理命令。

  • PUT

    用于放置指定的资源。在CouchDB PUT 用于创建新对象,包括数据库、文档、视图和设计文档。

  • DELETE

    删除指定的资源,包括文档、视图和设计文档。

  • COPY

    可用于复制文档和对象的特殊方法。

如果不支持指定类型的请求,则不支持该类型 405 - Method Not Allowed 将返回,列出支持的HTTP方法。例如:

{
    "error":"method_not_allowed",
    "reason":"Only GET,HEAD allowed"
}

1.1.2. HTTP头处理模块

因为CouchDB使用HTTP进行所有通信,所以您需要确保提供了正确的HTTP报头(并在检索时进行处理),以便获得正确的格式和编码。不同的环境和客户机对这些HTTP报头(尤其是不存在时)的效果会有或多或少的严格限制。如果可能,你应该尽可能具体。

1.1.2.1. 请求标头

  • Accept

    指定要由服务器返回的可接受数据类型的列表(即客户端可以接受/理解的数据类型)。格式应该是一个或多个MIME类型的列表,用冒号分隔。

    对于大多数请求,定义应该是针对JSON数据的 (application/json ). 对于附件,可以显式指定MIME类型,也可以使用 */* 指定支持所有文件类型。如果 Accept 未提供标头,则 */* 假设为MIME类型(即客户端接受所有格式)。

    使用 Accept 不需要CouchDB的in查询,但强烈建议使用它,因为它有助于确保客户端可以处理返回的数据。

    如果使用 Accept 头,CouchDB将使用 Content-type 返回了标题字段。例如,如果您明确请求 application/jsonAccept 对于请求,返回的HTTP头将使用返回的 Content-type 字段。

    例如,在发送没有显式 Accept 标题,或指定时 */*

    GET /recipes HTTP/1.1
    Host: couchdb:5984
    Accept: */*
    

    返回的标题是:

    HTTP/1.1 200 OK
    Server: CouchDB (Erlang/OTP)
    Date: Thu, 13 Jan 2011 13:39:34 GMT
    Content-Type: text/plain;charset=utf-8
    Content-Length: 227
    Cache-Control: must-revalidate
    

    注解

    返回的内容类型为 text/plain 即使请求返回的信息是JSON格式的。

    显式指定 Accept 标题:

    GET /recipes HTTP/1.1
    Host: couchdb:5984
    Accept: application/json
    

    返回的头包括 application/json 内容类型:

    HTTP/1.1 200 OK
    Server: CouchDB (Erlang/OTP)
    Date: Thu, 13 Jan 2013 13:40:11 GMT
    Content-Type: application/json
    Content-Length: 227
    Cache-Control: must-revalidate
    
  • Content-type

    指定请求中提供的信息的内容类型。规范使用MIME类型规范。对于大多数请求,这将是JSON (application/json ). 对于某些设置,MIME类型将是纯文本。上传附件时,它应该是附件或二进制文件对应的MIME类型 (application/octet-stream

    使用的 Content-type 强烈建议您提出要求。

1.1.2.2. 响应头

服务器在发回内容时返回响应头,并包含许多不同的头字段,其中许多是标准的HTTP响应头,对CouchDB操作没有意义。下面列出了对CouchDB很重要的响应头列表。

  • Cache-control

    cache-controlhttp响应头为客户机缓存机制提供了一个关于如何处理返回信息的建议。CouchDB通常返回 must-revalidate ,表示如果可能,应重新验证该信息。这用于确保正确更新内容的动态特性。

  • Content-length

    返回内容的长度(以字节为单位)。

  • Content-type

    指定返回数据的MIME类型。对于大多数请求,返回的MIME类型是 text/plain . 所有文本都是用Unicode(UTF-8)编码的,这在返回的 Content-type 作为 text/plain;charset=utf-8 .

  • Etag

    这个 Etag HTTP头字段用于显示文档或视图的修订。

    etag已分配给map/reduce组(单个设计文档中的视图集合)。对这些视图的任何索引的任何更改都将为单个设计文档中的所有视图url生成一个新的ETag,即使该特定视图的结果没有更改。

    _view URL有它自己的ETag,只有在对影响该索引的数据库进行更改时才会更新它。如果该特定视图的索引没有更改,则该视图将保留原始的ETag头(因此会发回) 304 - Not Modified 更多的时候)。

  • Transfer-Encoding

    如果响应使用编码,则在此头字段中指定。

    Transfer-Encoding: chunked 表示响应是分部分发送的,这种方法称为 chunked transfer encoding . 当CouchDB事先不知道它将要发送的数据的大小时(例如 changes feed

  • X-CouchDB-Body-Time

    接收请求正文所用的时间(毫秒)。

    当请求中包含正文内容时可用。

  • X-Couch-Request-ID

    请求的唯一标识符。

1.1.3. JSON基础知识

对CouchDB的大多数请求和响应都使用JavaScript对象表示法(JSON)来格式化数据和响应的内容和结构。

使用JSON是因为它是在web浏览器中处理数据的最简单和最简单的解决方案,因为JSON结构可以在web浏览器环境中作为JavaScript对象进行计算和使用。JSON还集成了CouchDB中使用的服务器端JavaScript。

JSON支持JavaScript支持的基本类型,这些基本类型包括:

  • 数组-括在方括号中的值列表。例如:

    ["one", "two", "three"]
    
  • 布尔值-a truefalse 价值观。你可以直接使用这些字符串。例如:

    { "value": true}
    
  • 数字-整数或浮点数。

  • 对象-一组键/值对(即关联数组或哈希)。键必须是字符串,但值可以是任何受支持的JSON值。例如:

    {
        "servings" : 4,
        "subtitle" : "Easy to make in advance, and then cook when ready",
        "cooktime" : 60,
        "title" : "Chicken Coriander"
    }
    

    在CouchDB中,JSON对象用于表示各种结构,包括主CouchDB文档。

  • 字符串-应该用双引号括起来,并支持Unicode字符和反斜杠转义。例如:

    "A String"
    

支持通过将JSON解析为JavaScript对象 JSON.parse() 函数,或通过各种库来执行将内容解析为JavaScript对象的函数。用于解析和生成JSON的库有很多种语言,包括Perl、Python、Ruby、Erlang等。

警告

应该注意确保您的JSON结构是有效的,无效的结构将导致CouchDB返回一个HTTP状态代码500(服务器错误)。

1.1.3.1. 处理编号

不熟悉计算机处理数字的开发人员和用户经常会遇到意外情况,因为他们认为以JSON格式存储的数字不一定会返回与逐个字符比较相同的数字。

JSON中定义的包含小数点或指数的任何数字都将通过erlangvm的“double”数据类型的思想进行传递。在视图中使用的任何数字都将通过视图服务器的数字概念(常见的JavaScript案例意味着,由于JavaScript对数字的定义,偶数整数都会通过double)。

考虑一下我们写给CouchDB的文档:

{
    "_id":"30b3b38cdbd9e3a587de9b8122000cff",
    "number": 1.1
}

现在让我们从CouchDB读回该文档:

{
    "_id":"30b3b38cdbd9e3a587de9b8122000cff",
    "_rev":"1-f065cee7c3fd93aa50f6c97acde93030",
    "number":1.1000000000000000888
}

所发生的是CouchDB正在改变解码结果的文本表示,并将其转换为某种数字格式。在大多数情况下,这是一个 IEEE 754 双精度浮点数,几乎所有其他语言都使用这个数字。

Erlang与其他语言有一点不同的是,它不尝试以最短的字符数打印结果输出。例如,这就是我们建立这种关系的原因:

ejson:encode(ejson:decode(<<"1.1">>)).
<<"1.1000000000000000888">>

令人困惑的是,这两种格式在内部解码成相同的IEEE-754表示。更重要的是,当它通过我们所知道的所有主要解析器时,它将被解码成一个相当接近的表示。

虽然我们只讨论了文本表示形式发生变化的情况,但另一个重要的情况是输入值包含的精度超过了在double中实际表示的精度。(如果您不接受数字是以双精度存储的,您可能会争辩说,这种情况实际上是在“丢失”数据)。

下面是作者机器上两个更常见的JSON库的日志:

位于CouchDB sha 168a663b的Ejson(CouchDB的当前解析器):

$ ./utils/run -i
Erlang R14B04 (erts-5.8.5) [source] [64-bit] [smp:2:2] [rq:2]
[async-threads:4] [hipe] [kernel-poll:true]

Eshell V5.8.5  (abort with ^G)
1> ejson:encode(ejson:decode(<<"1.01234567890123456789012345678901234567890">>)).
<<"1.0123456789012346135">>
2> F = ejson:encode(ejson:decode(<<"1.01234567890123456789012345678901234567890">>)).
<<"1.0123456789012346135">>
3> ejson:encode(ejson:decode(F)).
<<"1.0123456789012346135">>

节点::

$ node -v
v0.6.15
$ node
JSON.stringify(JSON.parse("1.01234567890123456789012345678901234567890"))
'1.0123456789012346'
var f = JSON.stringify(JSON.parse("1.01234567890123456789012345678901234567890"))
undefined
JSON.stringify(JSON.parse(f))
'1.0123456789012346'

Python ::

$ python
Python 2.7.2 (default, Jun 20 2012, 16:23:33)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
import json
json.dumps(json.loads("1.01234567890123456789012345678901234567890"))
'1.0123456789012346'
f = json.dumps(json.loads("1.01234567890123456789012345678901234567890"))
json.dumps(json.loads(f))
'1.0123456789012346'

红宝石::

$ irb --version
irb 0.9.5(05/04/13)
require 'JSON'
=> true
JSON.dump(JSON.load("[1.01234567890123456789012345678901234567890]"))
=> "[1.01234567890123]"
f = JSON.dump(JSON.load("[1.01234567890123456789012345678901234567890]"))
=> "[1.01234567890123]"
JSON.dump(JSON.load(f))
=> "[1.01234567890123]"

注解

在Ruby上,它需要一个顶级的对象或数组,所以我只包装了这个值。显然,它不会影响解析数字的结果。

Spidermonkey::

$ js -h 2>&1 | head -n 1
JavaScript-C 1.8.5 2011-03-31
$ js
js> JSON.stringify(JSON.parse("1.01234567890123456789012345678901234567890"))
"1.0123456789012346"
js> var f = JSON.stringify(JSON.parse("1.01234567890123456789012345678901234567890"))
js> JSON.stringify(JSON.parse(f))
"1.0123456789012346"

正如您所看到的,它们的行为基本相同,除了Ruby实际上似乎比其他库失去了一些精度。

敏锐的观察者会注意到ejson(CouchDB JSON库)报告了额外的三位数。虽然它很容易认为这是由于一些内部差异,但它只是上面描述的1.1输入的一个更具体的情况。

这里要注意的一点是,double只能保存有限数量的值。我们要做的是生成一个字符串,当它通过“标准”浮点解析算法(即, strtod )会在内存中产生与我们开始时相同的位模式。或者,稍有不同,JSON序列化数字中的字节被选择为引用一个double可以表示的单个特定值。

重要的一点是,我们是从一个无限集映射到一个有限集。一个简单的方法就是思考一下:

1.0 == 1.00 == 1.000 = 1.(infinite zeros)

显然,计算机不能容纳无限字节,所以我们必须将无限大的集合抽取成一个可以简洁表示的有限集合。

其他JSON库正在玩的游戏只是:

“要为double选择此特定值,我必须使用几个字符”

而且这个游戏有很多微妙的细节,如果不花大量的精力,很难在C语言中复制(Python花了一年多的时间才把它与那些自动运行在许多不同架构上的奇特构建系统进行分类)。

希望我们已经证明CouchDB并没有通过改变输入来做任何“奇怪”的事情。它的行为与任何其他常见的JSON库相同,只是打印输出不太好。

另一方面,如果你真的处于这样一个位置,IEEE-754双精度对你的数字来说不是一个令人满意的数据类型,那么答案就是不要通过这个表示传递你的数字。在JSON中,这是通过将它们编码为字符串或使用整数类型来实现的(尽管如果使用的平台的整数表示形式与普通的JavaScript不同,那么整数类型仍然会咬到你)。

可以很容易地找到更多信息,包括 Floating Point GuideDavid Goldberg's Reference .

另外,如果有人真的对改变这种行为感兴趣,我们会全神贯注地倾听 jiffy (理论上,当我们开始更新构建系统时,它将取代ejson)。我们寻找灵感的地方是TCL和Python。如果你知道一个不错的浮动打印算法的实现给我们一个叫嚣。

1.1.4. 状态代码HTTP

当CouchDB的接口通过HTTP工作时,使用HTTP状态代码号和响应数据体中的相应数据的组合来报告错误代码和状态。

CouchDB返回的错误代码列表以及相关错误的一般描述如下。特定请求类型的不同状态代码的含义在相应的API调用引用中提供。

  • 200 - OK

    请求已成功完成。

  • 201 - Created

    文档创建成功。

  • 202 - Accepted

    请求已被接受,但相应的操作可能尚未完成。这用于后台操作,例如数据库压缩。

  • 304 - Not Modified

    请求的附加内容尚未修改。它与ETag系统一起用于标识返回信息的版本。

  • 400 - Bad Request

    错误的请求结构。此错误可能表示请求URL、路径或标头有错误。所提供的MD5哈希和内容之间的差异也会触发此错误,因为这可能表明消息已损坏。

  • 401 - Unauthorized

    使用提供的授权无法使用请求的项目,或者未提供授权。

  • 403 - Forbidden

    禁止请求的项目或操作。

  • 404 - Not Found

    找不到请求的内容。内容将包括进一步的信息,如果可用的话,作为JSON对象。结构将包含两个键, errorreason . 例如:

    {"error":"not_found","reason":"no_db_file"}
    
  • 405 - Method Not Allowed

    对请求的URL使用无效的HTTP请求类型发出了请求。例如,您请求 PUT 当A POST 是必需的。这种类型的错误也可以由无效的URL字符串触发。

  • 406 - Not Acceptable

    服务器不支持请求的内容类型。

  • 409 - Conflict

    请求导致更新冲突。

  • 412 - Precondition Failed

    来自客户端的请求标头与服务器的功能不匹配。

  • 413 - Request Entity Too Large

    单据超出配置的 couchdb/max_document_size 值或整个请求超过 chttpd/max_http_request_size 价值。

  • 415 - Unsupported Media Type

    支持的内容类型以及请求或提交的信息的内容类型表明不支持该内容类型。

  • 416 - Requested Range Not Satisfiable

    服务器无法满足请求标头中指定的范围。

  • 417 - Expectation Failed

    批量发送文档时,批量加载操作失败。

  • 500 - Internal Server Error

    请求无效,原因可能是提供的JSON无效,或者请求中提供了无效信息。