首页 > 代码库 > 前端01.http协议回顾

前端01.http协议回顾

一、http1.0和1.1之间有什么区别?

http1.0 :每一次请求/响应都会建立并关闭一次连接,相应速度慢。

http1.1:在同一个tcp连接中,可以传输多个响应或请求。http1.1默认还开启长连接。

二、客户端请求。

GET / HTTP/1.1 #动作和http协议的版本号 

Host: www.test.com:8088  #客户端访问的主机地址

Connection: keep-alive  #长连接

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8  #当前浏览器所能解析的数据类型

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36  #客户端的操作系统以及浏览器等信息。

Accept-Encoding: gzip, deflate, sdch  #浏览器用来告诉服务器,自己支持的编码类型。

Accept-Language: zh-CN,zh;q=0.8 #浏览器当前的语言信息。

客户端请求头,大概分为四部分:

请求首行;  #请求方式 请求路径 协议和版本,例如:GET /index.html HTTP/1.1

请求头信息;# 请求头名称:请求头内容,即为key:value格式,例如:Host:localhost

空行;     #用来与请求体分隔开

请求体。   # GET没有请求体,只有POST有请求体。

GET请求

特点

http默认的请求方式为get。

get请求没有任何请求体。

一个get请求,大小一定在1k之内。

get请求的内容,会暴露在地址栏中。

产生get请求的操作:

在浏览器地址栏中输入一个URL,这一定会是个get请求。

点击页面上的一个连接,也会是一个get请求。

提交表单,默认情况下是get,可以设置为post。

下面是一个浏览器去访问百度搜索时,产生的请求头信息:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

#浏览器用来告诉服务器,自己这里可以解析的文档类型,其实这里包含了*/*,就表示什么都可以接收。

Accept-Encoding:gzip, deflate, sdch

#支持的压缩格式。数据在网络上传递时,可能服务器会把数据压缩后再发送

Accept-Language:zh-CN,zh;q=0.8

#当前客户端支持的语言,可以在浏览器的工具选项中找到语言相关信息

Cache-Control:max-age=0

Connection:keep-alive

#浏览器告诉服务端支持长链接的方式,保持一段时间链接,默认为3000ms

Cookie:BAIDUID=7AD83D51481D0BE4DB3250B5273A7A01:FG=1; BIDUPSID=7AD83D51481D0BE4DB3250B5273A7A01; PSTM=1483207633; BCLID=599596736169088288; 

#因为不是第一次访问这个地址,所以会在请求中把上一次服务器响应中发送过来的Cookie在请求中一并发送去过;这个Cookie的名字为BAIDUUID,FG,BIDUPSID.PSTM,BCLID。

#如果对cookie不理解的话,可以先把cookie当成一个字典,这个字典里可以放多组键值对,

BDSFRCVID=B9_sJeCGQG04CSbZK5LXuyRgDeKKnW7TH6aP2rQCi3AO4CkVJ2uIEG0Ptf8g0KubaKiaogKK0gOTH65P; H_BDCLCKID_SF=tJAD_CtatD-3ejrnhCTVMt_e2x7-2D62aKDssR3n-hcqEp3hQT0MLptVW44tWtntMGrMKn5cWbrRMUbSj4QmDRDuLUue3x4J0K3paDoaWl5nhMJmb67JDMP0-xQia4oy523ion3vQpP-MftuD6-ajjO0DG8sKC62atoLBRjOMJnqD6rnhPF3QJT3KP6-3MbI3b4J5MOtyqkh8hRG2q5JQ-LUyUTUth37JD6Totol0bI5EqAmLPR4y6D0ytoxJpOJ5JbMopvaKJjvjJjvbURvD--g3-Aqtl8EtJAD_CtatD-3ejrnhCTVMt_e2x7-2D62aKDs5DT7-hcqEp3hQT0MLptVW44tWpvtMGrMKn5cWbrRMUbSj4QmDRDuLUue3x4J0K3paDoaWl5nhMJmb67JDMP0-xQia4oy523ion3vQpP-Mftu-n5jHjJ0DNt83e; BD_CK_SAM=1; PSINO=1; BD_UPN=123253; H_PS_645EC=c485lXcS%2F7FBtERrH33%2FHldUI6NyBW8PijQ%2F%2F54A4h75m4RucmVSSJDxXBg; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDSVRTM=0; BD_HOME=0; H_PS_PSSID=1454_21081_21673_20930; __bsi=12503378464846675469_00_815_R_N_6_0303_C02F_N_I_I_0

Host:www.baidu.com

Upgrade-Insecure-Requests:1

User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36

Referer:http://www.baidu.com 

#注意!!referer这个标记,只有在通过其他url上连接过来之后,才会产生,请求来自哪个页面,例如你在百度上点击链接到了这里,那么Referer:http://www.baidu.com;如果你是在浏览器的地址栏中直接输入的地址,那么就没有Referer这个请求头了。

    2.post请求。

特点:

请求的数据不会出现在地址栏中。(提交给服务端的参数,都会被放进请求体。)

数据的大小无上限。

有请求体。

当遇到中文会使用url编码。

在这解释下什么是url编码。

我们都知道Http协议中参数的传输是"key=value"这种简直对形式的,如果要传多个参数就需要用“&”符号对键值对进行分割。如"?name1=value1&name2=value2",这样在服务端在收到这种字符串的时候,会用“&”分割出每一个参数,然后再用“=”来分割出参数值。

针对“name1=value1&name2=value2”我们来说一下客户端到服务端的概念上解析过程: 

  上述字符串在计算机中用ASCII吗表示为: 

  6E616D6531 3D 76616C756531 26 6E616D6532 3D 76616C756532。 

   6E616D6531:name1 

   3D:= 

   76616C756531:value1 

   26:&

   6E616D6532:name2 

   3D:= 

   76616C756532:value2 

   服务端在接收到该数据后就可以遍历该字节流,首先一个字节一个字节的吃,当吃到3D这字节后,服务端就知道前面吃得字节表示一个key,再想后吃,如果遇到26,说明从刚才吃的3D到26子节之间的是上一个key的value,以此类推就可以解析出客户端传过来的参数。

   现在有这样一个问题,如果我的参数值中就包含=或&这种特殊字符的时候该怎么办。 

比如说“name1=value1”,其中value1的值是“va&lu=e1”字符串,那么实际在传输过程中就会变成这样“name1=va&lu=e1”。我们的本意是就只有一个键值对,但是服务端会解析成两个键值对,这样就产生了奇异。

如何解决上述问题带来的歧义呢?解决的办法就是对参数进行URL编码 

   URL编码只是简单的在特殊字符的各个字节前加上%,例如,我们对上述会产生奇异的字符进行URL编码后结果:“name1=va%26lu%3D”,这样服务端会把紧跟在“%”后的字节当成普通的字节,就是不会把它当成各个参数或键值对的分隔符。

说道了post请求,在补充两个请求头的标记:

Content-Type: application/x-www-form-urlencoded:表单的数据类型,说明会使用url格式编码数据;url编码的数据都是以“%”为前缀,后面跟随两位的16进制。

Content-Length:13:请求体的长度,这里表示13个字节。

三、服务端响应头。

服务器回复给客户端的响应报头大概分为3部分。

响应头信息,空行,响应体。

Request URL:http://127.0.0.1:8090/login/ 

#客户端请求的url

Request Method:GET

#客户端请求的动作

Status Code:200 OK

#返回给客户端的状态码

Remote Address:127.0.0.1:8090

Response Headers

view source

Content-Type:text/html; charset=utf-8

#服务端当前应答给客户端的数据类型是什么,以及字符编码

Date:Wed, 26 Oct 2016 06:48:50 GMT

#响应时间

Server:WSGIServer/0.2 CPython/3.5.2

#服务端类型

X-Frame-Options:SAMEORIGIN

#响应体

Request URL:http://127.0.0.1:8090/login/

Request Method:GET

Status Code:200 OK

Remote Address:127.0.0.1:8090

Response Headers

view source

Content-Type:text/html; charset=utf-8

Date:Wed, 26 Oct 2016 06:48:50 GMT

Server:WSGIServer/0.2 CPython/3.5.2

X-Frame-Options:SAMEORIGIN

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

<form action="/login/" method="post">

  用户名:<input type="text" name="username"/>

  <input type="submit" value="http://www.mamicode.com/提交"/>

</form>    

</body>

</html>

   

HTTP/1.1 200 OK:响应协议为HTTP1.1,状态码为200,表示请求成功,OK是对状态码的解释;

Server:WSGIServer/0.2 CPython/3.5.2:服务器的版本信息;

Content-Type: text/html;charset=UTF-8:响应体使用的编码为UTF-8;

Content-Length: 724:响应体为724字节;

Set-Cookie: JSESSIONID=C97E2B4C55553EAB46079A4F263435A4; Path=/hello:响应给客户端的Cookie;

Date: Wed, 25 Sep 2012 04:15:03 GMT:响应的时间,这可能会有8小时的时区差

关于状态码做一个小的补充:

200,403,404,50x 这些状态码太常见了,在这里不做过多说明,主要说下302和304。

302:地址跳转,重定向,当响应码为302时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头Location,它指定了新请求的URL地址。

304:假如说,用户第一次通过浏览器向服务器请求一个资源文件比如说一个html文件。

服务器在应答的时候,会加一个Last-Modified的响应头,这个响应头说明了这个html文件最后的修改时间,浏览器会把这个html文件的内容,以及最后的响应时间记录下来。

当用户第二次请求这个html文件时,在请求头中,会包含一个IF-Modified-since的请求头,这个请求头对应的值就是,第一次向服务器发起请求时,服务器通过Last-Modified响应头发给客户端的值,也就是浏览器要请求的这个资源文件的最后修改时间。

If-Modified-Since请求头就是在告诉服务器,我这里浏览器缓存的这个文件最后修改时间是否和服务器端这个文件的最后的修改时间相等,如果相等,那么服务端直接就返回304就不用再响应这个文件的内容,浏览器会把缓存的内容直接显示出来。

而服务器端会获取If-Modified-Since值,与浏览器缓存的文件当前最后修改时间比对,如果相同,服务器会发响应码304,表示index.html与浏览器上次缓存的相同,无需再次发送,浏览器可以显示自己的缓存页面,如果比对不同,那么说明index.html已经做了修改,服务器会响应200。

下面是图解:

四、关于http协议的一些误区纠正。

http这种协议是一种无状态协议,没有任何记忆能力,浏览器一旦打开了服务器发来的网页,那么浏览器和服务器之间就没有任何联系了。

其实很多网上商城的购物车功能,都需要借助于Cookie或Session或服务器端API记录这些信息,请求服务器结算页面时同时将这些信息提交到服务器。

当你登录到一个网站时,你的登录状态也是由Cookie或Session来“记忆”的,因为服务器并不知道你是否登录。

说道这里,可能有人会问,既然http是无状态协议,那么保持的长连接是个什么鬼?

用一句话来说就是,无状态不代表HTTP不能保持TCP连接!

从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。

keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。

五、其他一些常见的响应头补充。

这些头都会导致浏览器不缓存。

Expires: -1;

Cache-Control: no-cache;

Pragma: no-cache;

具有刷新的功能,3秒后自动跳转到http://www.baidu.com。

#Refresh#: 时间;url=http://www.baidu.com

这些响应头在html中都是可以自定义的!!

在HTMl页面中可以使用来指定响应头,例如在index.html页面中给出,表示浏览器只会显示index.html页面3秒,然后自动跳转到http://www.baidu.com.


本文出自 “reBiRTH” 博客,请务必保留此出处http://suhaozhi.blog.51cto.com/7272298/1928820

前端01.http协议回顾