• restful架构


    参考1参考2

    RESTful架构,一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用

    起源 REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的

    Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。这个词组的翻译是"表现层状态转化",如果一个架构符合rest原则,我们就称它为restful架构

    资源(resources)

    rest翻译为表现层状态转化,它没有指名是谁的表现层,缺乏主语,在这里,我们用资源当做主语,即为资源的表现层状态转化。

    所谓资源,就是网络上的一个实体,它可以是一张图片,一段文本。。。我们可以用一个url指向它,用户通过url就能访问到这个资源。

    普及两个概念 uri与url,uri(统一资源标识符 Uniform Resource Identifier),url(统一资源定位符 Uniform Resource Locator),其中url是uri的子集

    表现层(representation)

    资源是一种信息实体,它可以有多种外在表现,比如文本可以以txt格式表现,也可以用html,json,xml格式表现,我们把资源具体呈现出的形式叫做它的表现层。

    uri指向资源,但不代表资源的形式,http头部中的accept和content-type等表达了资源的形式

    状态转化(state transfer)

    访问一个uri,就代表客户和服务器发生了一个交互,这个过程会涉及到数据和状态的变化。

    互联网通信协议http协议,是无状态的,不能记录资源的各种状态,资源的状态保存在服务器端,如果要操作服务器上的资源,就要通过一些手段,让服务器知道,从而让服务器的资源发生状态转化,这个变化是建立在表现层之上的,就是表现层状态转化。

    客户端使用的手段,只能是http协议,http协议里有很多操作方式的动词比如get,post,put,delete,它们对应了四种基本操作,get用来获取资源(查),post用来新建资源(增)或者修改资源(改),put用来更新资源(改),delete用来删除资源(删)。

    综上

    restfull架构即为

    每个url指向一种资源,客户端和服务器之间传递资源的某种表现层,客户通过4个http动词,对服务器资源进行操作,实现服务器资源表现层状态转化

    常见误区

    url中含有动词,比如/users/update/1,其中update是动词(手段),这个url就不满足restful架构,正确的写法是/user/1,然后用put方式或post方式

    url中带有版本号,不同版本,可以理解为同一资源的不同表现形式,可以把版本号放到http头信息中,从url剔除

     restful api设计

    一、协议

    api与用户的通信协议采用http协议

    二、域名

    尽量将api部署到专用域名下,比如 http://api.test.com。如果api不多且比较简单,不太会进一步扩展,也可以放到主域名下,比如http://test.com/api/...

    三、版本(version)

    将版本号放到http头信息中,也有说法说版本号放到url中更方便直接,github的是放在http头信息里的

    四、路径(endpoint)

    路径又称“终点”(endpoint),表示api具体网址,在restful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,比如说一个api提供动物园zoo信息,其中包括各种动物以及雇员信息,符合restful架构的url可如下设计

    • http://api.test.com/zoos 
    • http://api.test.com/animals
    • http://api.test.com/employees
    • http://api.test.com/zoo/1

    五、http动词

    对于资源的具体操作类型,由http动词表示,常用的http动词如下

    • get(select),从服务器获取资源(一项或多项)
    • post(create),在服务器新建一个资源
    • put(update),在服务器更新资源(客户端提供改变后的完整资源)
    • patch(update),在服务器更新资源(客户端提供改变的属性)比如svn中针对修改打patch操作
    • delete(delete),从服务器删除资源

    两个不常用http动词

    • head,获取资源元数据
    • options,获取信息,关于资源的哪些属性是客户端可以修改的

    例子如下

    • get /zoos,获取所有动物园
    • post /zoos,新建一个动物园
    • get /zoo/id,获取某个指定动物园的信息
    • put /zoo/id,更新某个指定动物园信息(提供该动物园修改后的完整信息)
    • patch /zoo/id,更新某个指定动物园信息(提供该动物园部分信息)
    • delete /zoo/id, 删除某个动物园
    • get /zoos/id/animals,获取指定动物园的所有动物
    • delete /zoos/id/anamal/id,删除指定动物园的指定动物

    六、信息过滤(filter)

    如果资源数量过多,服务器不好一次性全部返回给用户,api应该提供参数,过滤返回结果,比如指定筛选条件,排序,分页,限制返回数量等

    • ?animalType=1,指定筛选条件
    • ?sort=age&order=desc,排序
    • ?page=2&perPage=10,分页
    • ?limit=10,限制返回数量

    参数设计允许冗余,即允许api路径与url参数偶尔重复,比如 get /zoos/id/animals与 get /animals?zooId=id含义相同

    七、状态码(status code)

    服务器向用户返回的状态码和提示信息,常见的列表以下

    • 200 OK - [get],服务器成功返回用户请求的数据,该操作是幂等的(idempotent)
    • 201 CREATED - [post/put/patch],用户新建或修改数据成功
    • 202 ACCEPTED - [*],表示请求已进入后台排队(异步任务)
    • 204 NO CONTENT - [delete],用户数据删除成功
    • 400 INVALID REQUEST - [post/put/patch],用户发出的请求错误,服务器没有进行新建或修改数据的操作,该操作幂等
    • 401 Unauthorized - [*],用户没有权限(令牌,用户,密码错误)
    • 403 Forbidden - [*],表示用户得到授权(与401错误相对),但是访问是被禁止的
    • 404 NOT FOUND - [*],用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作幂等
    • 406 Not Acceptable - [get],用户请求的格式不可得(比如用户请求json格式,但是只有xml格式)
    • 410 Gone - [get],用户请求的资源被永久删除,且不会再得到
    • 500 INTERNAL SERVER ERROR - [*],服务器发生错误,用户将无法判断发出的请求是否成功

    八、错误处理(error handling)

     如果状态码是4xx,应该向用户返回错误信息,一般来说,返回的信息中将error作为键名,出错信息作为键值即可

    九、返回结果

    针对不同操作,服务器向用户返回的结果应该符合以下规范

    • get /collection 返回资源对象的列表(数组)
    • get /collection/resource 返回单个资源对象
    • post /collection 返回新生成的资源对象
    • put /collection/resource 返回完整的资源对象
    • patch /collection/resource 返回完整的资源对象
    • delete /collection/resource 返回一个空文档

    十、hypermedia api

    restful api最好做到hypermedia,即返回结果中信息丰富一点,提供链接,连向其他api方法,使得用户不用去查询文档,也知道下一步应该做什么。比如当用户向api.test.com的根目录发出请求时,得到的文档包含以下结果

    {
    "link":{ "rel": "collection http://api.test.com/zoos",
         "href": "http://api/test.com",
         "title": "list of zoos",
         "type": "application/vnd.yourformat+json"
    } }

     上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么api,rel代表这个api与当前网址的关系(collection关系,并给出该collection网址),href表示api路径,title表示api的标题,type表示返回类型。

    hypermedia api的设计也被称为HATEOAS,github的api就是这种设计,请求github的api会得到一个所有可用api网址列表

    {
      "current_user_url": "https://api.github.com/user",
      "current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",
      "authorizations_url": "https://api.github.com/authorizations",
      "code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
      "commit_search_url": "https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}",
      "emails_url": "https://api.github.com/user/emails",
      "emojis_url": "https://api.github.com/emojis",
      "events_url": "https://api.github.com/events",
      "feeds_url": "https://api.github.com/feeds",
      "followers_url": "https://api.github.com/user/followers",
      "following_url": "https://api.github.com/user/following{/target}",
      "gists_url": "https://api.github.com/gists{/gist_id}",
      "hub_url": "https://api.github.com/hub",
      "issue_search_url": "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
      "issues_url": "https://api.github.com/issues",
      "keys_url": "https://api.github.com/user/keys",
      "notifications_url": "https://api.github.com/notifications",
      "organization_repositories_url": "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
      "organization_url": "https://api.github.com/orgs/{org}",
      "public_gists_url": "https://api.github.com/gists/public",
      "rate_limit_url": "https://api.github.com/rate_limit",
      "repository_url": "https://api.github.com/repos/{owner}/{repo}",
      "repository_search_url": "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
      "current_user_repositories_url": "https://api.github.com/user/repos{?type,page,per_page,sort}",
      "starred_url": "https://api.github.com/user/starred{/owner}{/repo}",
      "starred_gists_url": "https://api.github.com/gists/starred",
      "team_url": "https://api.github.com/teams",
      "user_url": "https://api.github.com/users/{user}",
      "user_organizations_url": "https://api.github.com/user/orgs",
      "user_repositories_url": "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
      "user_search_url": "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
    }

    从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,会得到如下返回结果

    {
      "message": "Requires authentication",
      "documentation_url": "https://developer.github.com/v3/users/#get-the-authenticated-user"
    }

    返回结果给出了服务器的提示信息,以及相应文档地址

    十一、其他

    api的身份认证可以使用Oauth框架

    服务器返回的数据格式,尽量使用json,xml

    自动化测试工具java版参考

  • 相关阅读:
    原创 爱因斯坦迷题及推导过程
    惊闻姑姑家女婿去世,哀叹生命之脆弱,死亡如此接近
    京东自营预售逻辑
    自营SKU绑定逻辑
    自营结算解释&对账逻辑
    CPS逻辑
    京东搜索结果数据异常
    C++静态库中使用_declspec(dllexport) 不能导出函数的问题
    HTTP+SVN访问速度慢的问题
    Python log
  • 原文地址:https://www.cnblogs.com/peter-yan/p/8376440.html
Copyright © 2020-2023  润新知