您的位置:首页 > 理论基础 > 计算机网络

TCP/IP协议,HTTP协议--面试必备

2017-06-10 19:53 211 查看
经常面试被问到什么是http协议,什么是TCP协议,而且每次都弄不清楚,是时候记录一下了

一、什么是http协议?

如果读者对计算机网络的体系结构比较了解的话应该清楚,IP协议位于网络层,TCP/UDP协议位于传输层,HTTP位于应用层,如下图:



说明:

TCP是传输层协议,主要解决数据如何在网络中传输;HTTP协议是应用层协议,是TCP协议的上层协议,主要用于客户端与服务器 之间的数据传输

socket是对TCP协议的封装,是一个调用接口。

二、怎么发起HTTP请求?

其实发起一个HTTP请求就是建立一个socket连接,是不过HTTP请求是无状态且短链接的协议

浏览器在建立socket连接之前,先根据DNS服务器去把域名解析成对应的IP地址,将IP地址和默认的80端口(https请求和http类似,只不过他用的是443端口和证书)与服务器建立一个socket链接。

我们利用代码来模拟一下客户端的请求过程,具体代码:

URLConnection urlConnection = new URL("http://www.baidu.com").openConnection();
urlConnection.connect();
Map<String, List<String>> map = urlConnection.getHeaderFields();
for(String key:map.keySet()){
System.out.println(key+":"+map.get(key));
}


深入分析URLConnection代码发现,它的底层也是使用socket实现,sun.net.NetworkClient的内部实现:

protected Socket doConnect (String server, int port)
152     throws IOException, UnknownHostException {
153         Socket s;
154         if (proxy != null) {
155             if (proxy.type() == Proxy.Type.SOCKS) {
156                 s = AccessController.doPrivileged(
157                     new PrivilegedAction<Socket>() {
158                         public Socket run() {
159                                        return new Socket(proxy);
160                                    }});
161             } else if (proxy.type() == Proxy.Type.DIRECT) {
162                 s = createSocket();
163             } else {
164                 // Still connecting through a proxy
165                 // server & port will be the proxy address and port
166                 s = new Socket(Proxy.NO_PROXY);
167             }
168         } else
169             s = createSocket();
170         // Instance specific timeouts do have priority, that means
171         // connectTimeout & readTimeout (-1 means not set)
172         // Then global default timeouts
173         // Then no timeout.
174         if (connectTimeout >= 0) {
175             s.connect(new InetSocketAddress(server, port), connectTimeout);
176         } else {
177             if (defaultConnectTimeout > 0) {
178                 s.connect(new InetSocketAddress(server, port), defaultConnectTimeout);
179             } else {
180                 s.connect(new InetSocketAddress(server, port));
181             }
182         }
183         if (readTimeout >= 0)
184             s.setSoTimeout(readTimeout);
185         else if (defaultSoTimeout > 0) {
186             s.setSoTimeout(defaultSoTimeout);
187         }
188         return s;
189     }
190


三、浏览器怎么解析HTTP请求?

我们也可以通过curl/charles/wireshark来进行抓包分析HTTP数据包,下面我通过curl来查看http的请求头信息,命令如下:

HTTP 请求由三部分组成:请求行、 请求头和请求正文。

curl -v http://www.baidu.com[/code] 
请求头信息:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Cookie:BIDUPSID=FAB2DD0A535CCE85F60B0E747EDD2F80; PSTM=1493346210; BAIDUID=A132C53C54C0BD857558B3C9A0BE6888:FG=1; BDUSS=VxWWlZN2p3Z3I5a3hyejdvQ0ppVmxXcmNDcFhyckozT2t4RE5HRXRxall6UzlaSVFBQUFBJCQAAAAAAAAAAAEAAAAkHEsRenp4MDEwMTAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANhACFnYQAhZMX; BDSFRCVID=krPsJeC62xGbH8QZbUZhu8KOK2KfnEnTH6aomPIViliOVFyXv0lyEG0PqU8g0Kub5QsaogKK0mOTHvbP; H_BDCLCKID_SF=tb4q_I_aJCvbfP0kj502e5OQDa0jJI62aKDs0U5c-hcqEIL4jh85jIuuWmcPBUoaJnI8-bCa2R6RMxbSj4Qo3-INyx6UKf7bWnvnWnTCyp5nhMJI3j7JDMP0qtOkKxny523ion6vQpn-8UtuD6-bDj5WeHDs-bbfHjrtBRRV-bnHDR365DTjhPrMMp5TbMT-0bFHXp3tWInGoRoaW47heMPgyN5iKt64aHn7_JjOaxJzSRT1Mfn4QRFR5G3QhxQxtNRD-CnjtpvhHC5hKPQobUPUDMc9LUvqKH4E3-oJqCKhMDLm3H; BDRCVFR[S4-dAuiWMmn]=I67x6TjHwwYf0; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; BDRCVFR[dG2JNJb_ajR]=mk3SLVN4HKm; BD_CK_SAM=1; PSINO=2; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BD_HOME=1; H_PS_PSSID=1441_19033_21111_17001_19897_21670_22582; BD_UPN=123253; sugstore=1
Host:www.baidu.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36


常见请求头

GET
方法是默认的HTTP请求方法,例如当我们通过在浏览器的地址栏中直接输入网址的方式去访问网页的时候,浏览器采用的就是 GET 方法向服务器获取资源。

Host
(发送请求时,该报头域是必需的)

Host请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的。

Accept
:浏览器可以接受的媒体类型(MIME类型),

例如: Accept: text/html 代表浏览器可以接受服务器回发的类型为 text/html 也就是我们常说的html文档, 如果服务器无法返回text/html类型的数据,服务器应该返回一个406错误(non acceptable)。

通配符 * 代表任意类型。例如 Accept: / 代表浏览器可以处理所有类型,(一般浏览器发给服务器都是发这个)

User-Agent
:告诉HTTP服务器, 客户端使用的操作系统和浏览器的名称和版本.

我们上网登陆论坛的时候,往往会看到一些欢迎信息,其中列出了你的操作系统的名称和版本,你所使用的浏览器的名称和版本,这往往让很多人感到很神奇,实际上, 服务器应用程序就是从User-Agent这个请求报头域中获取到这些信息User-Agent请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器

Accept-Encoding
:浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate),(注意:这不是只字符编码);

例如: Accept-Encoding: gzip, deflate。Server能够向支持gzip/deflate的浏览器返回经gzip或者deflate编码的HTML页面。 许多情形下这可以减少5到10倍的下载时间,也节省带宽。

Accept-Language
: 浏览器申明自己接收的语言。

语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等;

例如: Accept-Language:zh-cn 。如果请求消息中没有设置这个报头域,服务器假定客户端对各种语言都可以接受。

Connection
:表示是否需要持久连接。

如果服务器看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,服务器需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入 ByteArrayOutputStream,然后在正式写出内容之前计算它的大小;

例如: 
Connection: keep-alive
当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的 网页,会继续使用这一条已经建立的连接 .
Connection: close
代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭, 当客户端再次发送Request,需要重新建立TCP连接

curl -I http://www.baidu.com[/code] 
响应头信息:

Accept-Ranges:[bytes]
null:[HTTP/1.1 200 OK]
Cache-Control:[private, no-cache, no-store, proxy-revalidate, no-transform]
Server:[bfe/1.0.8.18]
ETag:["588604c4-94d"]
Connection:[Keep-Alive]
Set-Cookie:[BDORZ=27315; max-age=86400; domain=.baidu.com; path=/]
Pragma:[no-cache]
Last-Modified:[Mon, 23 Jan 2017 13:27:32 GMT]
Content-Length:[2381]
Date:[Sat, 10 Jun 2017 03:38:14 GMT]
Content-Type:[text/html]


响应头常用信息:

状态行:状态行由协议版本、数字形式的状态代码,及相应的状态描述组成,各元素之间以空格分隔,结尾时回车换行符,例如:
HTTP/1.1 200 OK


Expires:浏览器会在指定过期时间内使用本地缓存,指明应该在什么时候认为文档已经过期,从而不再缓存它。

Set-Cookie: 非常重要的header, 用于把cookie 发送到客户端浏览器, 每一个写入cookie都会生成一个Set-Cookie.

Entity实体头域:实体内容的属性,包括实体信息类型,长度,压缩方法,最后一次修改时间,数据有效性等。

ETag:和If-None-Match 配合使用。

Last-Modified: 用于指示资源的最后修改日期和时间。

If-None-Match: If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息。 当用户再次请求该资源时,将在HTTP Request 中加入If-None-Match信息(ETag的值)。如果服务器验证资源的ETag没有改变(该资源没有更新),将返回一个304状态告诉客户端使用本地缓存文件。否则将返回200状态和新的资源和Etag. 使用这样的机制将提高网站的性能

Server:指明HTTP服务器的软件信息

Pragma:防止页面被缓存, 在HTTP/1.1版本中,它和
Cache-Control:no-cache
作用一模一样 ,Pargma只有一个用法, 例如:
Pragma: no-cache


Cache-Control: 这个是非常重要的规则。 这个用来指定Response-Request遵循的缓存机制。各个指令含义如下

Cache-Control:Public
可以被任何缓存所缓存()

Cache-Control:Private
内容只缓存到私有缓存中

Cache-Control:no-cache
所有内容都不会被缓存

Content-Length:指明实体正文的长度,以字节方式存储的十进制数字来表示。在数据下行的过程中,
Content-Length
的方式要预先在服务器中缓存所有数据,然后所有数据再一股脑儿地发给客户端。

Content-Encoding:文档的编码(Encode)方法。一般是压缩方式。

四、浏览器缓存是什么?

浏览器缓存一般是前端工程师必须要掌握的,但是,我们作为后端开发也需要了解一下,毕竟技多不压身。

它就是我们在打开一个有缓存的网页时,浏览器会将其自动下载保存到本地(副本)。我们一般通过ctrl+f5来强制刷新本地缓存。

Cache-Control
:缓存控制头信息,是关于浏览器缓存的最重要的设置,不仅可以控制浏览器,还可以覆盖其他设置(如Expires和Last-Modified)或代理服务器。另外,由于浏览器的行为基本相同,这个属性是处理跨浏览器缓存问题的最有效的方法。

Pragma
:与Cache-Control功能类似。Pragma属于通用首部字段,在客户端上使用时,常规要求我们往html上加上这段meta元标签,如:
<meta http-equiv="Pragma" content="no-cache">
用于告诉浏览器每次请求页面时都不要读缓存,都得往服务器发一次请求才行。

说明:仅有IE才能识别这段meta标签含义;它不一定会在请求字段加上Pragma,但的确会让当前页面每次都发新请求(仅限页面,页面上的资源则不受影响)。

Expires
:

过期头信息,通常后面跟一个时间,超过这个时间缓存内容将会失效。在客户端上使用时,我照样可以加上meta元标签,如:

<meta http-equiv="expires" content="Sun, 04 Jun 2017 14:40:01 GMT">


说明:同样也只有IE能够识别,如果希望每次刷新页面都能发新请求,那么可以把“content”里的值写为“-1”或“0”。Pragma字段的优先级会高于Pragma。

Last-Modified/ETag
缓存校验字段;用于判断控制文件是否有修改.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  http协议 面试 tcp tcp-ip