HTTP协议知多少

作为前端开发,HTTP和我们息息相关,因为我们的全部资源都是从server拿过来的,client只作为一个解析和呈现的终端,主要还是提供一个与用户进行交互的地方。

整体来说就是:计算机语言编译或解释执行各种资源、数据,向计算机发送各种指令,计算机凭借着高速的计算呈现出结果。

HTTP历史

一篇有逼格的文章怎么少得了历史

1989年,一个物理学家想做一个科学家之间分享知识的超文本文档网络。他称之为world wide web,随后他自己制作了服务器和客户端让网络世界降临。

这个物理学家就是tim berners-lee,他一手促成的WWW日后走入人们的日常生活,极大的促进了信息时代的发展。

其实在HTTP未出现的时候,FTP等协议早已出现,而berners-lee创新提出WWW技术包括HTTP协议,HTML标准以及客户端服务端等,意图实现其他应用层协议不能满足的一些需求,他心中的HTTP是这样的:

  1. 只要一部分的文件传输功能。http只要客户端单向发起,服务端单向响应。
  2. 自动在客户端服务器之间协商格式
  3. 引导客户端到别的服务器的能力
  4. http可以由作者放置长效文档,访问者可以通过输入url,或者html内嵌url的引导,访问得到这个文档。

这些简单而实用的思想伴随着互联网的浪潮,相对FTP、SMTP协议来说,非常年轻的HTTP飞速的发展起来了,直到今天,HTTP2已经飞入寻常百姓家。

我们进入正题,下面让我们看一个具体的实例吧。

这里写图片描述

如图所示,HTTP报文主要分为三部分,起始行,协议头,协议体(以下是不区分请求和响应来说的)

起始行

图中起始行主要有五部分:

  1. 请求协议,如HTTP
  2. 协议版本号,如1.0,关于HTTP2下面会有所介绍
  3. 状态码 标准的状态码有很多种,如200,403等,详细的情况可以看下面。
  4. URL(uniform resource locator) 统一资源定位符,表示你想要通信的资源位置
  5. 请求方法类型,主要向服务器传达不同的命令类型,表明了想要服务器操作资源方式的大概范围,详细的情况可以看下面。

HTTP method

HTTP1.0定义了三种方法,包括我们现在最常用的方法,GET, POST 和 HEAD方法。
HTTP1.1定义了五种方法,OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

  1. GET 我们最熟悉的方法,向指定URL请求信息,包括各种格式,请求体放在URL中
  2. HEAD 类似get请求,只不过请求返回的响应中没有具体的内容,只用于获取报头。
  3. POST 向指定URL提交数据进行处理请求,数据放在请求体中,post请求可能会导致新的资源的建立和旧的资源的修改。
  4. PUT 从客户端向服务端传送数据,取代指定文档的内容
  5. DELETE 请求服务器删除指定页面
  6. CONNECT HTTP1.1中预留出给能够将连接改为管道方式的代理服务器
  7. OPTIONS 允许客户端查看服务器性能
  8. TRACE 回显服务器收到的请求,主要用于测试或诊断

请求状态码

1** 信息,请求者收到请求,需要请求者继续请求服务
2** 成功,操作被成功接收并且处理
3** 重定向,需要进一步操作完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,在处理请求中发生错误

介绍几个比较常用的状态码
200 ok 请求成功
201 created 新建
204 no content 无内容

301 move permanently 资源永久重定向
302 move temporary 资源暂时重定向
303 see other 重定向链接指向的不是新上传的资源而是一个新页面
304 not modify 资源没有修改

400 bad request 语法错误
401 Unauthorized 没有权限
403 forbidden 禁止访问
404 not found 无法找到

500 internal server error 服务器内部错误
502 bad gateway 充当网关或代理的服务器,从远端服务器接收到了一个无效请求
503 service unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求

协议头

我们比较熟悉的部分,很多人都能随口说出不少

请求头实例

accept-ranges
服务器是否接受获取其某个实体的一部分的请求(比如文件的一部分),bytes:接受,none:不接受

content-type
服务器返回资源类型,包含资源类型以及具体格式,如text/html,application/xml,image/jpeg

access-control-allow-origin
是CORS(cross origin resource sharing)使用的字段,跨源资源共享,也是我们经常使用的跨域手段,这里表示接受任意跨域请求。

age
年龄,表示代理服务器用自己的缓存响应请求时,该实体从产生到现在多长时间了

cache-control
每个资源都可以通过cache-control设置缓存策略,包含是否允许缓存,缓存如何生效,缓存过期时间等,常用的如max-age,指允许响应被重用的最长时间,图中的意思即缓存有效期为315360000ms;如no-cache,表示必须先跟服务器判断响应结果是否发生变化再命中缓存,可以跟ETag进行配合。

其他的不多介绍了,如果有兴趣可以看我另一篇缓存相关的博客

etag
常用的缓存字段,标识一个资源的唯一字符串,可以理解为资源的版本号,起作用跟last-modify相似,client提供给server etag字段,server判断etag与当前服务器内资源etag是否相同。

expires
资源的过期时间,图中表示该资源2037年过期,在命中缓存时,若超过过期时间则需要向server验证资源有效性。

last-modify
server资源最后修改时间,图中表示当前请求时该资源最后变动在2016年

server
服务器类型以及版本号等信息

via
从client到server或相反方向资源传输路径中所经过的代理服务器信息,包括名称、协议、版本,每经过一个服务器,字段添加本服务器信息。

content-encoding
响应中资源对象压缩的方法,gzip,deflate,br等

transfer-encoding
服务器对响应字段做的编码处理,如chunked(分块),注意跟楼上进行区分,这是对整个HTTP请求内容进行的编码类型处理,楼上是response body部分的编码格式

vary
表示cache服务器什么时候可以用本响应所返回资源对象响应后续请求,配合content-encoding,如content-encoding:gzip,vary:content-encoding,表示资源对象使用gzip格式,并且当client可以接受gzip格式时响应请求。关系到命中缓存验证的一部分,当有后续请求在验证是否可以命中缓存时,cache服务器会根据前面两个字段和请求头中的accept-encoding,并决定是否命中缓存,主要是防止client对某些格式不能进行解码。

referer
页面或资源来源

协议体

协议体是报文的主体部分,是HTTP报文的负荷,也是我们主要的传输的内容,上面的两部分其实只是协议性质、属性的一部分,是让HTTP协议运转不可分割的一部分,而真正我们所需要的纯粹内容则是在协议体里面,包括图片、文字、视频等,当然最终的形态其实都是字节码的形式。

协议的意义

协议是什么?协议就是协商议论的成果。

经典的问题—从url输入到页面呈现其实很难说的完,整个链路很长,从一段段光纤到我们笔记本浏览器上的精彩页面,当然我们也知道,整个过程无疑是传送了一些信息频段而已,不同层次被解析成不同字节码,对照ascii码转换为字符、数字,然而中间如何知道起点终点、如何知道何时进行解析、如何知道传输错误、如何控制传输方式等,这些都是靠标准的协议解析相应的字段进行支撑的。

同时HTTP协议只是定义了方法的标准,并没有强制让你执行,你完全可以不遵守协议规则 ,也可以自己加自定义的字段,只不过识别还是需要浏览器进行,统一的标准能最大限度约束浏览器的实现(HTTP是标准,浏览器具体实现可能有略微的差距),进而可以更好、更快的将我们需要的信息传达出去,浏览器接收到解析后就会进行规定的行为。

Web API

说实话,对于写后端比较少的我来说,充分理解各种Web API还是有些困难的,若有不对之处还请指正。

按我理解,现在接口可能大概分为五类

  1. RPC接口
  2. SOAP接口
  3. 纯REST接口
  4. 类REST接口
  5. GraphQL

前两者不太熟悉,下面着重讲一下后三者吧

RPC

remote procedure call是一种计算机协议,它能够实现一台计算机A调用另一台计算机B中的程序,实际上也是通过定义好的request和response,进行了两台计算机之间的通信。

SOAP

simply object access protocol是web service进行带结构数据交换的一种协议,可以理解为是在无结构数据的基础上,大家遵从一定的约定,使数据传送的结果是附带结构的数据。

REST

representional state transfer(表述性状态转移),中文很抽象,理解起来确实有一定门槛,在我看来,其实REST更像一种风格或者说设计思想,其实REST比较早就被提出了(它是 Roy Thomas Fielding 博士于 2000 年在他的博士论文 “Architectural Styles and the Design of Network-based Software Architectures” 中提出来的),随着移动互联网来临,REST收到关注越来越多,早期的场景比较单一,前后端分离并不明确,后端3P(jsp,php,asp)模板接管前端,但随着技术发展和时代变迁,前端要求越来越高,并且client种类(mobile、pc等)越来越多,这时候REST就提供了一套比较好的解决方案。

按我的理解其实restful可能更多的是接口的设计原则,通过比较简洁、语义化更强的接口协议字段,实现更符合现在web开发趋势,能够快速迭代开发、后期维护方便的接口设计。

REST的核心是面向资源,可以理解为REST后端只是将database的很多关联表的资源归纳统一,比如数据库中的用户信息,可能存储到多张关联表上,如base表上有年龄、性别、爱好、姓名、id,公司表上又会有公司、职位、级别等,那么后端的呈现就会是一个“/user”的请求路径,当客户端发送一个GET请求到此路径,后端就多次select然后组成user的JSON资源响应前端。所以,我理解REST是以资源为核心,每个路径代表一种资源,通过不同的HTTP方法进行资源获取、修改等操作。

REST风格主要关注于,或者说主要优势是:

  1. 关注点分离
  2. 可见性、可靠性和可伸缩性
  3. 网络性能和效率
  4. 统一接口

下面来看下github的REST API

github API示例

当你发送了GET请求后,返回的response

emails response

关于REST,知乎的@Ivony老师的一句话概括很精辟:
URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。

画蛇添足补充一下,同时用约定俗成的status code来进行结果表示;数据也是通过一定格式进行传输,如上图的json格式;充分利用了HTTP header,传递重要信息,传输约定字段,启动约定功能,如缓存头cache-control,同源策略头access-control-allow-origin等。

大致讲了一下REST,能力有限可能略有失准或浅显,推荐大家自己搜资料深入学习一下,推荐深入理解REST,下面区分一下纯REST和类REST

纯REST

指一个路径代表一个(类、种)资源,跟上面讲的类似,其优点主要就是:

  1. 灵活,适配多端,资源映射路径
  2. 解耦,资源相对独立

另外当然也有一些缺点:

  1. 每个页面加载可能需要多次请求
  2. 可能会加载到不需要的资源(移动端流量损耗)
  3. 不同客户端需要根据比较严格的接口数据协议和自身端的情况进行不同的视图逻辑

可以看到REST的优点很棒,但缺点也很明显,特别是当你的需求、UI限制比较多的时候,一旦与REST API发生冲突后其实会浪费一些请求资源并且影响用户体验(串行多次请求)。

类REST

指一个路径对应一个视图的资源,请求该路径即可获得该视图(页面)的资源,相对于REST的缺点做了明显的改进,也有蛮多公司采用这种设计,其优点:

  1. 每个page一次请求
  2. 没有冗余资源

缺点:

  1. 不够灵活,资源只能由页面级别获取
  2. 耦合性强
  3. 维护代价比较高,业务变动后端逻辑随时修改
  4. 迭代缓慢,更改代价高,一端改变影响另一端

如果以耦合性和性能两种量度来看,其实两种设计分别是低耦合低性能,高耦合和高性能,如何在这二者之间做出取舍,其实还是要结合实际情况进行分析,比如当前移动端大行其道,网络情况平均较差,那么我们就应该更加关注性能。

那么有没有更好的解决方案呢?答案是有的

GraphQL

技术最早的意义就是服务于业务,而新技术的产生无非是以下两种原因 :

  1. 该技术所在领域产生了新趋势
  2. 原有的技术难以应对新趋势

进入移动互联网时代后,显而易见的对技术要求上升了一个等级

  1. 移动端性能要求比较高,要求获取数据更加高效
  2. 多端业务发展迅速,要求 API 灵活、按需提供资源、低耦合、易扩展

那么根据新趋势以及二者设计的优点,先梳理一下我们的需求:

  1. 灵活性,get what you need,不会有冗余数据
  2. 低耦合,资源相对独立
  3. 一个view只需请求一次资源

GraphQL就是我们的新选择,其是由facebook在2012年开发,2015年开源的成果,其在facebook内部已经广泛替代REST进行使用

那么GraphQL到底是什么呢?graphQL官方称其为查询语言,其实现了由客户端控制资源查询,相对于REST来说,它具有以下改进

graphQl的改进

GraphQL主要包含以下三部分

  1. 用于描述数据类型和关系的API定义语言(schema)

    type: Story{
        title: String,
        author: Author,
        comments: [Comment],
        score: Int
    }
    
    type: Query{
        top(limit: Int): [Story]
    }

    用类似C语言中的struct关键字来描述各数据相互之间关系,从而形成比较直观的树形包含结构,如Query类型中包含Story类型组合成数组,Story类型中包含Comment类型组合成的数组以及其他字段。

  2. 可以描述具体需要获取哪些数据的查询语言(query)

    query{
        top{
            title
            url
            by{
                id
                karma
            }
        }
    }
  3. 描述数据单个属性的可执行模型(resolve function)

    function top(root, args){
        return storiesCollection.find()
            .sort({score: -1})
            .limit(args.limit)
    }

    resolve function决定了query对应的response,可以将REST的资源路径对应业务逻辑跟GraphQL的resolve function进行类比,二者都是进行request分析、数据库操作以及response生成等行为。

从前后端角度来看,这其实是把REST后端的功能交给了前端,资源不再是由后端定死,而是前端灵活请求。

接下来我们看实例

{
  user(id: 3500401) {
    id,
    name,
    isViewerFriend
  }
}
// result
{
  "user" : {
    "id": 3500401,
    "name": "Jing Chen",
    "isViewerFriend": true
  }
}


{
  user(id: 3500401) {
    name,
    profilePicture(size: 50)  {
      uri,
      width,
      height
    }
  }
}
// result
{
  "user" : {
    "name": "Jing Chen",
    "profilePicture": {
      "uri": "http: //someurl.cdn/pic.jpg",
      "width": 50,
      "height": 50
    }
  }
}

GraphQL是一种规范,提供了一种client灵活查询数据的范式,更多是将后端变得灵活,打破原有的REST路径对应资源的模式,而使用GraphQL的resolve function对传递的query进行约定的解析以及响应,从而client可以按需进行资源请求,保证性能以及维护迭代。

HTTPS

HTTPS采用的是对称+非对称加密算法,众所周知非对称一般情况下会更加安全,但是非对称加密解密过程比较复杂,效率较低,所以HTTPS采用非对称进行连接建立和对称秘钥的传输,当秘钥传输完毕后就只采用对称加密算法进行网络传输。正因为HTTPS要在正式传输数据时进行一系列准备工作,所以HTTPS一般来说会比HTTP慢建立连接。

HHTPS流程

  1. 浏览器发出安全请求
    一般升级HTTPS都是可以优雅降级的,在不能使用HTTPS时降到HTTP,同时,当你支持HTTPS时,你访问HTTP域名也会自动转到HTTPS,到目前为止,HTTPS普及度还是比较高的,门槛也不高。

  2. 服务器会返回数字证书(包含公钥)

  3. 浏览器检查数字证书
    使用CA列表验证了证书(主要看签名)后,我们即可得到服务器的公钥,之所以要通过CA—证书授权中心(Certificate Authority ),是因为我们要保证服务器公钥的安全传输。

  4. 浏览器生成对称秘钥,并使用服务器公钥进行加密
    在非对称加密中传输给服务器将要使用对称秘钥

  5. 服务器使用自己的私钥进行解密,得到对称秘钥

  6. 双方知道了对称秘钥,加密通信

web socket

细知识点

CONNRCT 方法

关于HTTP协议中的CONNECT方法,上次面试问过,特意查了些资料,记录在此吧。

MDN中使这么下定义的:CONNECT方法可以开启一个客户端与所请求资源的双向沟通的通道,它可以用来创建隧道。

例如,CONNECT可以用来访问SSL协议站点,客户端要求代理服务器将TCP连接作为通往目的主机隧道,之后该服务器会代替客户端与目的主机进行连接。连接建立好之后,代理服务器会面向客户端发送或接收TCP信息流。

get post区别

get和post应该是我们最常接触到的两个方法,其实google一下还是有很多标准答案的,这里我主要是根据RFC方法定义进行比较

The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI. If the Request-URI refers to a data-producing process, it is the produced data which shall be returned as the entity in the response and not the source text of the process, unless that text happens to be the output of the process.

意译一下:GET方法意味着取回请求统一资源标识符标识的信息。如果这个请求统一资源标识符对应的是数据生成过程,那么生成的数据将作为实体响应请求,如果对应的是源文本(即不需要数据生成过程)则直接作为响应实体。

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. POST is designed to allow a uniform method to cover the following functions:
    - Annotation of existing resources;

      - Posting a message to a bulletin board, newsgroup, mailing list,or similar group of articles;

      - Providing a block of data, such as the result of submitting a form, to a data-handling process;

      - Extending a database through an append operation.

    The actual function performed by the POST method is determined by the server and is usually dependent on the Request-URI. The posted entity is subordinate to that URI in the same way that a file is subordinate to a directory containing it, a news article is subordinate to a newsgroup to which it is posted, or a record is subordinate to a database.

   The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.

   If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header (see section 14.30).

   Responses to this method are not cacheable, unless the response includes appropriate Cache-Control or Expires header fields. However, the 303 (See Other) response can be used to direct the user agent to retrieve a cacheable resource.

意译一下:POST方法向源服务器发出请求,服务器会接收请求实体作为URI的从属资源,POST方法会被拥有下列功能的方法统一处理:

  1. 现有资源的注释(我理解为保存现有资源的一些情况,包括缓存等)
  2. 将信息发送到公告栏、新闻组、邮件列表或相似的文章组中(我理解为进行数据处理吧)
  3. 提供一个数据块,例如提交一个表单的结果,以及数据处理过程
  4. 通过添加操作扩展数据库

POST方法的实际功能取决于服务端,进一步说通常是依赖请求的资源标识符。请求实体与资源标识符的从属关系类似于一个文件从属于包含文件夹,一个新闻文章从属于新闻组,一条记录从属于数据库。

POST方法的行为导致一种资源不会唯一对应一种资源标识符。在这种情况下,适当的响应状态是200(ok)还是204(no content),取决于响应是否包含一个描述结果的实体。

如果一个资源被源服务器创建,这个响应状态码为201(created),包含一个描述请求状态的实体,并引用新资源和位置消息头。

POST方法的响应式不可缓存的,除非响应包含准确的cache-control、expires头。303(see other)响应能用来指引用户代理取回一个可缓存资源。

这么一看区别其实还是很显然的
- GET的语义为请求获取指定资源,GET方法是安全、幂等、可缓存的(除非有 Cache-ControlHeader的约束),GET方法的报文主体没有任何语义。
- POST的语义是根据请求负荷(报文body)对指定的资源做出处理,具体的处理方式视资源类型而不同。POST不安全,不幂等,(大部分实现)不可缓存。

301和302区别

先前提过HTTP中status code表示结果,3***代表重定向,而301(Permanently Moved)永久重定向和302(Temporarily Moved)暂时重定向正是3***中出现频率最高的。

1. 搜索引擎处理不同
301和302的语义区别代表着浏览器会对其进行不同的操作,就搜索引擎而言

  • 301代表永久换了地址,搜索引擎会将这两个地址的搜索权重加在一起
  • 302代表暂时换了地址,搜索引擎会将两个地址分别进行处理,二者不会相互关联

当然随着搜索引擎的发展,301和302的结果也并不是一定绝对,比如你把302当做301使用,即永久换地址的情况下使用302,当二者重定向次数、持续时间变长时,搜索引擎会将事实上的永久重定向按实际情况处理,即二者权重看为一体,那么这时候如果你重定向地址变化了,搜索引擎也不会重复爬取了,这就会造成一定问题,另外302还会造成URL劫持,网站被封等问题,所以使用301和302一定要注意。

2. 浏览器处理不同

  • 301一般会缓存
  • 302不会被浏览器缓存

根据语义不同,301是可以缓存的,因为你是永久性迁移,不会出现命中错误缓存的情况,而302如果缓存了并且执行地址频繁变化,那么很容易命中错误缓存,所以正确使用301和302也是用户体验的重要一部分。

相关链接

  1. HTTP协议头部与Keep-Alive模式详解
  2. 关于HTTP协议,一篇就够了
  3. Referrer 还是 Referer?
  4. HTTP 代理原理及实现(一)
  5. 这里写链接内容
  6. 聊聊60分的Web API
  7. 从REST到GraphQL—2017jsconf演讲文档
  8. Node.js 服务端实践之 GraphQL 初探
  9. http状态码301和302详解及区别
  10. 说说URL重定向的301和302类型
  11. Http状态码之:301、302重定向
  12. JavaScript之web通信
  13. GraphQL 初探—面向未来 API 及其生态圈

比较小白的理解,希望深入学习、使用后可以结合协议标准进行更深入的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值