http协议

http header

HTTP(HyperTextTransferProtocol)即超文本传输协议,目前网页传输的的通用协议。HTTP协议采用了请求/响应模型,浏览器或其他客户端发出请求,服务器给与响应。就整个网络资源传输而言,包括message-header和message-body两部分。首先传递message- header,即http header消息 。http header 消息通常被分为4个部分:general  header, request header, response header, entity header。但是这种分法就理解而言,感觉界限不太明确。根据维基百科对http header内容的组织形式,大体分为Request和Response两部分。

Requests部分

Header
解释
示例
Accept 指定客户端能够接收的内容类型 Accept: text/plain, text/html
Accept-Charset 浏览器可以接受的字符编码集。 Accept-Charset: iso-8859-5
Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。 Accept-Encoding: compress, gzip
Accept-Language 浏览器可接受的语言 Accept-Language: en,zh
Accept-Ranges 可以请求网页实体的一个或者多个子范围字段 Accept-Ranges: bytes
Authorization HTTP授权的授权证书 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Cache-Control 指定请求和响应遵循的缓存机制 Cache-Control: no-cache
Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) Connection: close
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 Cookie: $Version=1; Skin=new;
Content-Length 请求的内容长度 Content-Length: 348
Content-Type 请求的与实体对应的MIME信息 Content-Type: application/x-www-form-urlencoded
Date 请求发送的日期和时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
Expect 请求的特定的服务器行为 Expect: 100-continue
From 发出请求的用户的Email From: user@email.com
Host 指定请求的服务器的域名和端口号 Host: www.zcmhi.com
If-Match 只有请求内容与实体相匹配才有效 If-Match: “737060cd8c284d8af7ad3082f209582d”
If-Modified-Since 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
If-None-Match 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 If-None-Match: “737060cd8c284d8af7ad3082f209582d”
If-Range 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag If-Range: “737060cd8c284d8af7ad3082f209582d”
If-Unmodified-Since 只在实体在指定时间之后未被修改才请求成功 If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
Max-Forwards 限制信息通过代理和网关传送的时间 Max-Forwards: 10
Pragma 用来包含实现特定的指令 Pragma: no-cache
Proxy-Authorization 连接到代理的授权证书 Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Range 只请求实体的一部分,指定范围 Range: bytes=500-999
Referer 先前网页的地址,当前请求网页紧随其后,即来路 Referer: http://www.zcmhi.com/archives/71.html
TE 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 TE: trailers,deflate;q=0.5
Upgrade 向服务器指定某种传输协议以便服务器进行转换(如果支持) Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
User-Agent User-Agent的内容包含发出请求的用户信息 User-Agent: Mozilla/5.0 (Linux; X11)
Via 通知中间网关或代理服务器地址,通信协议 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning 关于消息实体的警告信息 Warn: 199 Miscellaneous warning

Responses 部分 

Header
解释
示例
Accept-Ranges 表明服务器是否支持指定范围请求及哪种类型的分段请求 Accept-Ranges: bytes
Age 从原始服务器到代理缓存形成的估算时间(以秒计,非负) Age: 12
Allow 对某网络资源的有效的请求行为,不允许则返回405 Allow: GET, HEAD
Cache-Control 告诉所有的缓存机制是否可以缓存及哪种类型 Cache-Control: no-cache
Content-Encoding web服务器支持的返回内容压缩编码类型。 Content-Encoding: gzip
Content-Language 响应体的语言 Content-Language: en,zh
Content-Length 响应体的长度 Content-Length: 348
Content-Location 请求资源可替代的备用的另一地址 Content-Location: /index.htm
Content-MD5 返回资源的MD5校验值 Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==
Content-Range 在整个返回体中本部分的字节位置 Content-Range: bytes 21010-47021/47022
Content-Type 返回内容的MIME类型 Content-Type: text/html; charset=utf-8
Date 原始服务器消息发出的时间 Date: Tue, 15 Nov 2010 08:12:31 GMT
ETag 请求变量的实体标签的当前值 ETag: “737060cd8c284d8af7ad3082f209582d”
Expires 响应过期的日期和时间 Expires: Thu, 01 Dec 2010 16:00:00 GMT
Last-Modified 请求资源的最后修改时间 Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
Location 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 Location: http://www.zcmhi.com/archives/94.html
Pragma 包括实现特定的指令,它可应用到响应链上的任何接收方 Pragma: no-cache
Proxy-Authenticate 它指出认证方案和可应用到代理的该URL上的参数 Proxy-Authenticate: Basic
refresh 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持)
 

 
Refresh: 5; url=
http://www.zcmhi.com/archives/94.html

Retry-After 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 Retry-After: 120
Server web服务器软件名称 Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
Set-Cookie 设置Http Cookie Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Trailer 指出头域在分块传输编码的尾部存在 Trailer: Max-Forwards
Transfer-Encoding 文件传输编码 Transfer-Encoding:chunked
Vary 告诉下游代理是使用缓存响应还是从原始服务器请求 Vary: *
Via 告知代理客户端响应是通过哪里发送的 Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
Warning 警告实体可能存在的问题 Warning: 199 Miscellaneous warning
WWW-Authenticate 表明客户端请求实体应该使用的授权方案 WWW-Authenticate: Basic

文件上传下载

 

http-client文件上传

大家通过HTTP向服务器发送POST请求提交数据,都是通过form表达提交的,代码如下:


  1. <form method="post" action="http://w.sohu.com">

  2. <input type="text" name="txt1">

  3. <input type="text" name="txt2">

  4. </form>


提交时会向服务器段发出这样的数据(已经去除部分不相关的头信息),数据如下:


  1. POST / HTTP/1.1

  2. Content-Type:application/x-www-form-urlencoded

  3. Accept-Encoding: gzip, deflate

  4. Host: w.sohu.com

  5. Content-Length: 21

  6. Connection: Keep-Alive

  7. Cache-Control: no-cache

  8.  

  9. txt1=hello&txt2=world

  10.  


对于普通的HTML Form POST请求,它会在头信息里使用Content-Length注明内容长度。头信息每行一条,空行之后便是Body,即"内容"(entity)。它的Content-Type是application/x-www-form-urlencoded,这意味着消息内容会经过URL编码,就像在GET请求时URL里的QueryString那样。txt1=hello&txt2=world.

POST上传文件

最早的HTTP POST是不支持文件上传的,给编程开发带来很多问题。但是在1995年,ietf出台了rfc1867,也就是<RFC 1867-Form-based File Upload in HTML>,用以支持文件上传。所以Content-Type的类型扩充了multipart/form-data用以支持向服务器发送二进制数据。因此发送post请求时候,表单<form>属性enctype共有两个值可选,这个属性管理的是表单的MIME编码:

   ①application/x-www-form-urlencoded(默认值)

   ②multipart/form-data

其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype="application/x-www-form-urlencoded".

通过form表单提交文件操作如下:


  1. <form method="post" action="http://w.sohu.com/t2/upload.do" enctype="multipart/form-data">

  2. <input type="text" name="desc">

  3. <input type="file" name="pic">

  4. </form>


浏览器将会发送以下数据:


POST /t2/upload.do HTTP/1.1

User-Agent: SOHUWapRebot

Accept-Language: zh-cn,zh;q=0.5

Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7

Connection: keep-alive

Content-Length: 60408

Content-Type: multipart/form-data;boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Host: w.sohu.com

 

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="desc"

Content-Type: text/plain; charset=UTF-8

Content-Transfer-Encoding: 8bit

 

[......][......][......][......]..........

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC

Content-Disposition: form-data;name="pic";filename="photo.jpg"

Content-Type: application/octet-stream

Content-Transfer-Encoding: binary

 

[图片二进制数据]

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--

  1.  


我们来分析下数据,第一个空行之前自然还是HTTP header,之后则是Entity,而此时的Entity也比之前要复杂一些。根据RFC 1867定义,我们需要选择一段数据作为"分隔边界"(boundary属性),这个"边界数据"不能在内容其他地方出现,一般来说使用一段从概率上说"几乎不可能"的数据即可。不同的浏览器的实现不同,例如火狐某次post的boundary=---------------------------32404670520626 ,opera为 boundary=----------E4SgDZXhJMgNE8jpwNdOAX ,每次post浏览器都会生成一个随机的30-40位长度的随机字符串,浏览器一般不会遍历这次post的所有数据找到一个不可能出现的数据中的字符串,这样代价太大了。一般都是随机生成, 如果你遇见boundary值和post的内容一样,那样的话这次上传肯定失败,不过我建议你去买彩票,你太幸运了。rfc 1867这样说明{A boundary is selected that does not occur in any of the data.(This selection is sometimes done probabilisticly.)}。

     选择了这个边界之后,浏览器便把它放在Content-Type里面传递给服务器,服务器根据此边界解析数据。下面的数据便根据boundary划分段,每一段便是一项数据。(每个field被分成小部分,而且包含一个value是"form-data"的“Content-Disposition"的头部;一个"name"属性对应field的ID,等等,文件的话包括一个filename).

  • IE和Chrome在filename的选择策略上有所不同,前者是文件的完整路径,而后者则仅仅是文件名。
  • 数据内容以两条横线结尾,并同样以一个换行结束。在网络协议中一般都以连续的CR、LF(即\r、\n,或0x0D, 0x0A)字符作为换行,这与Windows的标准一致。如果您使用其他操作系统,则需要考虑他们的换行符。

另外Content-length指的是所用数据的长度。

实现

httpClient4如何实现

httpClient4使用http-mime.jar包的MultipartEntity实现,代码如下:


HttpPost httpPost = newHttpPost(url);

Log.debug("post url:"+url);

httpPost.setHeader("User-Agent", "SOHOWapRebot");

httpPost.setHeader("Accept-Language", "zh-cn,zh;q=0.5");

httpPost.setHeader("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.7");

httpPost.setHeader("Connection", "keep-alive");

 

MultipartEntity multiEntity = new MultipartEntity();

File file = new File("d:/photo.jpg");

multiEntity.addPart("desc", new StringBody("美丽的西双版纳", Charset.forName("utf-8")));

multiEntity.addPart("pic", newFileBody(file));

 

httpPost.setEntity(multiEntity);

HttpResponse httpResponse = httpClient.execute(httpPost);

HttpEntity httpEntity = httpResponse.getEntity();

String content = EntityUtils.toString(httpEntity);

http-client文件下载

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

/**
* 说明
* 利用httpclient下载文件
* maven依赖
* <dependency>
* <groupId>org.apache.httpcomponents</groupId>
* <artifactId>httpclient</artifactId>
* <version>4.0.1</version>
* </dependency>
* 可下载http文件、图片、压缩文件
* bug:获取response header中Content-Disposition中filename中文乱码问题
* @author tanjundong
*
*/
public class HttpDownload {

public static final int cache = 10 * 1024;
public static final boolean isWindows;
public static final String splash;
public static final String root;
static {
if (System.getProperty("os.name") != null && System.getProperty("os.name").toLowerCase().contains("windows")) {
isWindows = true;
splash = "\\";
root="D:";
} else {
isWindows = false;
splash = "/";
root="/search";
}
}

/**
* 根据url下载文件,文件名从response header头中获取
* @param url
* @return
*/
public static String download(String url) {
return download(url, null);
}

/**
* 根据url下载文件,保存到filepath中
* @param url
* @param filepath
* @return
*/
public static String download(String url, String filepath) {
try {
HttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
HttpResponse response = client.execute(httpget);

HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
if (filepath == null)
filepath = getFilePath(response);
File file = new File(filepath);
file.getParentFile().mkdirs();
FileOutputStream fileout = new FileOutputStream(file);
/**
* 根据实际运行效果 设置缓冲区大小
*/
byte[] buffer=new byte[cache];
int ch = 0;
while ((ch = is.read(buffer)) != -1) {
fileout.write(buffer,0,ch);
}
is.close();
fileout.flush();
fileout.close();

} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取response要下载的文件的默认路径
* @param response
* @return
*/
public static String getFilePath(HttpResponse response) {
String filepath = root + splash;
String filename = getFileName(response);

if (filename != null) {
filepath += filename;
} else {
filepath += getRandomFileName();
}
return filepath;
}
/**
* 获取response header中Content-Disposition中的filename值
* @param response
* @return
*/
public static String getFileName(HttpResponse response) {
Header contentHeader = response.getFirstHeader("Content-Disposition");
String filename = null;
if (contentHeader != null) {
HeaderElement[] values = contentHeader.getElements();
if (values.length == 1) {
NameValuePair param = values[0].getParameterByName("filename");
if (param != null) {
try {
//filename = new String(param.getValue().toString().getBytes(), "utf-8");
//filename=URLDecoder.decode(param.getValue(),"utf-8");
filename = param.getValue();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return filename;
}
/**
* 获取随机文件名
* @return
*/
public static String getRandomFileName() {
return String.valueOf(System.currentTimeMillis());
}
public static void outHeaders(HttpResponse response) {
Header[] headers = response.getAllHeaders();
for (int i = 0; i < headers.length; i++) {
System.out.println(headers[i]);
}
}
public static void main(String[] args) {
// String url = "http://bbs.btwuji.com/job.php?action=download&pid=tpc&tid=320678&aid=216617";
String url="http://www.dy1000.com/img/20120701/1999311085_150_200.JPG";
// String filepath = "D:\\test\\a.torrent";
String filepath = "D:\\test\\a.jpg";
HttpDownload.download(url, filepath);
}
}


cookie

存储客户端的状态

京东商城在没有登陆的情况下依然可以将商品加入购物车,那么这个购物车的数据存储到哪里呢?肯定不是request,因为如果是它的话,每加入一件,再去访问其它商品,在加入一件,上一次商品就没有了,因为Http协议是无状态的,也就是说每个客户访问服务器端资源时,在未登录的情况下,服务器并不知道该客户端是谁,所以需要会话技术识别客户端的状态。会话技术是帮助服务器记住客户端状态

会话技术Cookie和Session

从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,成为一次会话。会话技术就是记录这次会话中客户端的状态与数据的。

Cookie:数据存储在客户端本地,减少服务器端的存储的压力,安全性不好,客户端可以清除cookieSession:将数据存储到服务器端,安全性相对好,增加服务器的压力

Cookie技术详解

 

创建Cookie

Cookie cookie = new Cookie(String cookieName,String cookieValue);

参数为cookie的名称和cookie的值,举例:Cookie cookie = new Cookie("username","zhangsan");

那么创建了一个cookie,并且向cookie中写入了数据username=zhangsan,注意cookie中不能写入中文,也就是说后面的验证码效验,如果是中文验证码,则不能用cookie

如果我们将这个cookie向客户端发送,那么相应头的形式是这样的

 

设置Cookie在客户端的持久化时间

cookie.setMaxAge(int seconds);seconds为秒

cookie默认的生命周期是一个会话,就是说只要浏览器关系,他就没有了,如果不设置持久化时间,cookie会存储在浏览器的内存中,浏览器关闭cookie信息销毁(会话级别的cookie),如果设置持久化时间,cookie信息会被持久化到浏览器的磁盘文件里,设置多久时间,他就会存在多长时间

举例:

设置cookie信息在浏览器的磁盘文件中存储的时间是10分钟,过期浏览器自动删除该cookie信息cookie.setMaxAge(10*60);

设置Cookie的携带路径

如果不设置携带路径,那么该cookie信息会在访问产生该cookie的web资源所在的路径都携带cookie信息,比如/aa/servlet的这个路径的servlet产生了cookie,那么只有在访问WWW/aa下的资源的时候才会带cookie,如果访问WWW/a.jsp则不会带cookie,因为他不是aa目录下的

示例:

cookie.setPath("/WEB16");代表访问WEB16应用中的任何资源都携带cookiecookie.setPath("/WEB16/cookieServlet");代表访问WEB16中的cookieServlet时才携带cookie信息cookie.setPath("/");访问服务器下的所有应用都携带这个cookie

向客户端发送cookie:

response.addCookie(Cookie cookie);创建完成之后,只有发送才能到答响应体

删除客户端的cookie:

如果想删除客户端的已经存储的cookie信息,那么就使用同名同路径的持久化时间为0的cookie进行覆盖即可

new相同name值的cookie,值无所谓(new相同的name的cookie会把前面相同name的覆盖)设置相同的setpath,最好设置最大Age为0,才删除,必须全部一样然后response.Add(这个cookie)向响应头增加一个set-cookie字段

第一次浏览器访问网站因为没有cookie,所以请求行没有cookie,假如他访问的servlet,new了一个cookie,并且response。add这个cookie,那么下次浏览器在访问这个网站资源(如果setpath合适的话),他会在请求头中带上这个cookie

 

那么我们此时可以通过request获取这个cookie,并且解析里面的值

1)通过request获得所有的Cookie:(只能获取所有)Cookie[] cookies = request.getCookies();2)遍历Cookie数组,通过Cookie的名称获得我们想要的Cookiefor(Cookie cookie : cookies)}

一个cookie创建的时候只能添加一个键值对,一个web站点可以给web浏览器发送多个cookie,一个浏览器也可以存储多个cookie,一般允许存放300个cookie,每个网站允许存放20个

http code


HTTP: Status 100 (继续)
-> 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
HTTP: Status 101 (切换协议)
-> 请求者已要求服务器切换协议,服务器已确认并准备切换。

HTTP Status 200 (成功)
-> 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
HTTP Status 201 (已创建)
-> 请求成功并且服务器创建了新的资源。
HTTP Status 202 (已接受)
-> 服务器已接受请求,但尚未处理。
HTTP Status 203 (非授权信息)
-> 服务器已成功处理了请求,但返回的信息可能来自另一来源。
HTTP Status 204 (无内容)
-> 服务器成功处理了请求,但没有返回任何内容。
HTTP Status 205 (重置内容)
-> 服务器成功处理了请求,但没有返回任何内容。
HTTP Status 206 (部分内容)
-> 服务器成功处理了部分 GET 请求。

HTTP Status 400 (错误请求)
->服务器不理解请求的语法。
HTTP Status 401 (未授权)
->请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
HTTP Status 403 (禁止)
-> 服务器拒绝请求。
HTTP Status 404 (未找到)
->服务器找不到请求的网页。
HTTP Status 405 (方法禁用)
->禁用请求中指定的方法。
HTTP Status 406 (不接受)
->无法使用请求的内容特性响应请求的网页。
HTTP Status 407 (需要代理授权)
->此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
HTTP Status 408 (请求超时)
->服务器等候请求时发生超时。
HTTP Status 409 (冲突)
->服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
HTTP Status 410 (已删除)
-> 如果请求的资源已永久删除,服务器就会返回此响应。
HTTP Status 411 (需要有效长度)
->服务器不接受不含有效内容长度标头字段的请求。
HTTP Status 412 (未满足前提条件)
->服务器未满足请求者在请求中设置的其中一个前提条件。
HTTP Status 413 (请求实体过大)
->服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
HTTP Status 414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
HTTP Status 415 (不支持的媒体类型)
->请求的格式不受请求页面的支持。
HTTP Status 416 (请求范围不符合要求)
->如果页面无法提供请求的范围,则服务器会返回此状态代码。
HTTP Status 417 (未满足期望值)
→服务器未满足”期望”请求标头字段的要求。


HTTP Status 500 (服务器内部错误)
->服务器遇到错误,无法完成请求。
HTTP Status 501 (尚未实施)
->服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
HTTP Status 502 (错误网关)
->服务器作为网关或代理,从上游服务器收到无效响应。
HTTP Status 503 (服务不可用)
-> 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
HTTP Status 504 (网关超时)
->服务器作为网关或代理,但是没有及时从上游服务器收到请求。
HTTP Status 505 (HTTP 版本不受支持)
-> 服务器不支持请求中所用的 HTTP 协议版本。

http 1.0、1.1、2.0区别

一、HTTP1.0 HTTP 1.1主要区别

      1.1 长链接

            HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。

               HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响。因此最好能维持一个长连接,可以用个长连接来发多个请求。


      1.2 节约带宽

          HTTP 1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,否则返回401。客户端如果接受到100,才开始把请求body发送到服务器。

 

            这样当服务器返回401的时候,客户端就可以不用发送请求body了,节约了带宽。

 

           另外HTTP还支持传送内容的一部分。这样当客户端已经有一部分的资源后,只需要跟服务器请求另外的部分资源即可。这是支持文件断点续传的基础
       

     1.3HOST域

        现在可以web server例如tomat,设置虚拟站点是非常常见的,也即是说,web server上的多个虚拟站点可以共享同一个ip和端口。

        HTTP1.0是没有host域的,HTTP1.1才支持这个参数。

 

二、 HTTP 1.1、HTTP2.0主要区别

    2.1  多路复用

         HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。

 

           当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。

 

           TCP连接有一个预热和保护的过程,先检查数据是否传送成功,一旦成功过,则慢慢加大传输速度。因此对应瞬时并发的连接,服务器的响应就会变慢。所以最好能使用一个建立好的连接,并且这个连接可以支持瞬时并发的请求。

     2.2  数据压缩

       HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。

    2.3  服务器推送

         当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。

       服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。

         服务端推送过来的资源,会统一放在一个网络与http缓存之间的一个地方,在这里可以理解为“本地”。当客户端把index.html解析完以后,会向本地请求这个资源。由于资源已经本地化,所以这个请求的速度非常快,这也是服务端推送性能优势的体现之一。

https

Https涉及到的主体

  1. 客户端。通常是浏览器(Chrome、IE、FireFox等),也可以自己编写的各种语言的客户端程序。
  2. 服务端。一般指支持Https的网站,比如github、支付宝。
  3. CA(Certificate Authorities)机构。Https证书签发和管理机构,比如Symantec、Comodo、GoDaddy、GlobalSign。

下图里我画出了这几个角色:
Https Role

发明Https的动机

  1. 认证正在访问的网站。什么叫认证网站?比如你正在访问支付宝,怎样确定你正在访问的是阿里巴巴提供的支付宝而不是假冒伪劣的钓鱼网站呢?
  2. 保证所传输数据的私密性和完整性。众所周知,Http是明文传输的,所以处在同一网络中的其它用户可以通过网络抓包来窃取和篡改数据包的内容,甚至运营商或者wifi提供者,有可能会篡改http报文,添加广告等信息以达到盈利的目的。

Https的工作流程

这一节通过介绍Https协议的工作流程,来说明Https是如何达成自己的两个目的的。下图我画出了Https的工作流程,注意,这只是原理示意图,并不是详细的协议解析。

Https Flow

可以看到工作流程,基本分为三个阶段:

  1. 认证服务器。浏览器内置一个受信任的CA机构列表,并保存了这些CA机构的证书。第一阶段服务器会提供经CA机构认证颁发的服务器证书,如果认证该服务器证书的CA机构,存在于浏览器的受信任CA机构列表中,并且服务器证书中的信息与当前正在访问的网站(域名等)一致,那么浏览器就认为服务端是可信的,并从服务器证书中取得服务器公钥,用于后续流程。否则,浏览器将提示用户,根据用户的选择,决定是否继续。当然,我们可以管理这个受信任CA机构列表,添加我们想要信任的CA机构,或者移除我们不信任的CA机构。

  2. 协商会话密钥。客户端在认证完服务器,获得服务器的公钥之后,利用该公钥与服务器进行加密通信,协商出两个会话密钥,分别是用于加密客户端往服务端发送数据的客户端会话密钥,用于加密服务端往客户端发送数据的服务端会话密钥。在已有服务器公钥,可以加密通讯的前提下,还要协商两个对称密钥的原因,是因为非对称加密相对复杂度更高,在数据传输过程中,使用对称加密,可以节省计算资源。另外,会话密钥是随机生成,每次协商都会有不一样的结果,所以安全性也比较高。

  3. 加密通讯。此时客户端服务器双方都有了本次通讯的会话密钥,之后传输的所有Http数据,都通过会话密钥加密。这样网路上的其它用户,将很难窃取和篡改客户端和服务端之间传输的数据,从而保证了数据的私密性和完整性。

使用Https的流程

如果你是一个服务器开发者,想使用Https来保护自己的服务和用户数据安全,你可以按照以下流程来操作。

CA Flow

总结

  1. 说是讨论Https,事实上Https就是Http跑在SSl或者TLS上,所以本文讨论的原理和流程其实是SSL和TLS的流程,对于其它使用SSL或者TLS的应用层协议,本文内容一样有效。
  2. 本文只讨论了客户端验证服务端,服务端也可以给客户端颁发证书并验证客户端,做双向验证,但应用没有那么广泛,原理类似。
  3. 由于采用了加密通讯,Https无疑要比Http更耗费服务器资源,这也是很多公司明明支持Https却默认提供Http的原因。

http调试工具之PostMan

 

posted @ 2021-08-23 09:08  无敌的小小哒  阅读(223)  评论(0编辑  收藏  举报