Web Api 内部数据思考 和 利用http缓存优化 Api

在上篇《Web Api 端点设计 与 Oauth》后,接着我们思考Web Api 的内部数据:

其他文章:《API接口安全加强设计方法

第一  实际使用应该返回怎样的数据 ?

  如何减少api访问次数非常重要,但是我们会遇到,当我们尽可能的返回多的信息,多的字段,那么一次请求,将会带来大量的毫无意义的信息。当我们尽可能的节约,那么客户端需要多次请求才能拿到想要的数据,于是高不成,低不就。

     优化方法:让客户端来选择响应的内容,例:

http://api.example.com/v1/users/12345?fields=name,age

通过fields来指定想要返回的字段,那么还可以进行怎样的分类呢?

  利用响应群来获取想要的数据

small :
字段1,字段2,字段3

medium:
字段1,字段2,字段3,字段4,字段5,字段6

large:
字段1,字段2,字段3,字段4,字段5,字段6,字段7,字段8

  通过分配group参数,来指定想要的哪些群组

第二 状态码是否必要?

  我们来看一下某些数据:

{
     “status” : {
          "result" : "success",
          "errorCode" : 0,
    }
     "response" :{
          .......实际的数据......
    }

}    

  我们写接口常常有这个习惯,将状态码写于返回值中,这样也可以,但我们经常忽略了,web api 大部分都是基于http协议,可以说http已经完成了封装的工作。http协议首部可以放置状态码,可以选择合适的状态码来返回。然而很多人都没有处理这个状态吗。我以前在对接的过程中,便和对接的公司产生了歧义。

  返回的json数据中的code是0,失败的错误码,但对方提出了问题,为什么已经返回失败的错误码,但你们的http状态码是为200.

  回到问题本身,我个人认为状态码是需要的,但同时也要做好http状态码的处理,这样做出来的api不容易让人产生误解。

第三 数据是否应该扁平化 ?

  我们来看两个例子:

具有层级关系的:
{
    "id" : 1111 ,
    "message" : "hello" ,
    "sender" : {
            "id" : 123,
            .......
            }
    "receiver" : {
            "id" : 123,
            ......
        }

}
使用扁平化的方式:
{
    "id" : 1111 ,
    "message" : "hello" ,
    "sender_id" : 123,
    "sender_....." : ....,
    "receiver_id" : 123
    "receiver_...." : ....,
}

这种情况我们要具体分析,上述那种情况,可以明显的看出接受方receive,和发送方send,那么此时用层级关系比较好

而像下述这种情况:

使用层级形式:

{
    "id" : 23245,
    "name" : 'xxx',
    "profile" :{
        "birthday" : 45,
        "gender" : "male",
    }
}

使用扁平化方式:

{
    "id" : 23245,
    "name" : 'xxx',
    "birthday" : 45,
    "gender" : "male",
}

这种情况下,使用层级跟使用扁平化没什么区别,而使用层级还会让json的尺寸变大,那我们可以在此用扁平化

第四 状态码太多,大致分类是?

HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:

HTTP状态码分类

分类

分类描述

1**

信息,服务器收到请求,需要请求者继续执行操作

2**

成功,操作被成功接收并处理

3**

重定向,需要进一步的操作以完成请求

4**

客户端错误,请求包含语法错误或无法完成请求

5**

服务器错误,服务器在处理请求的过程中发生了错误

 罗列各种状态码我就不罗列了。

利用http缓存优化 Api

 一)强制缓存

        强制缓存,在缓存数据未失效的情况下,可以直接使用缓存数据,那么浏览器是如何判断缓存数据是否失效呢?在没有缓存数据的时候,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。
  对于强制缓存来说,响应header中会有两个字段来标明失效规则(Expires/Cache-Control)
使用chrome的开发者工具,可以很明显的看到对于强制缓存生效时,网络请求的情况

    Expires
  Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。
不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。
另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。
所以HTTP 1.1 的版本,使用Cache-Control替代。

  Cache-Control
   Cache-Control 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
  private:             客户端可以缓存
  public:              客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的)
  max-age=xxx:   缓存的内容将在 xxx 秒后失效
  no-cache:          需要使用对比缓存来验证缓存数据(后面介绍)
  no-store:           所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多越好,so...基本上和它说886)

 例如:

图中Cache-Control仅指定了max-age,所以默认为private,缓存时间为31536000秒(365天)
也就是说,在365天内再次请求这条数据,都会直接获取缓存数据库中的数据,直接使用。

 

 二)对比缓存
  
对比缓存,顾名思义,需要进行比较判断是否可以使用缓存。
  浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
  再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使  用缓存数据。
第一次访问:

再次访问:

通过两图的对比,我们可以很清楚的发现,在对比缓存生效时,状态码为304,并且报文大小和请求时间大大减少。
原因是,服务端在进行标识比较后,只返回header部分,通过状态码通知客户端使用缓存,不再需要将报文主体部分返回给客户端。

对于对比缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,
一共分为两种标识传递:

Last-Modified  /  If-Modified-Since
Last-Modified:
服务器在响应请求时,告诉浏览器资源的最后修改时间。

If-Modified-Since:
再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。
服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。
若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;
若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。



Etag  /  If-None-Match(优先级高于Last-Modified  /  If-Modified-Since)
服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。


If-None-Match:
再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。
服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对,
不同,说明资源又被改动过,则响应整片资源内容,返回状态码200;
相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。

 

posted @ 2017-08-03 14:28 hongxinerke 阅读(...) 评论(...) 编辑 收藏