1. 浏览器如何发起一个HTTP请求?
浏览器在建立Socket连接之前,必须根据地址栏输入的 URL 的域名 DNS 解析出IP地址,再根据 IP 地址和默认的80端口与远程服务器建立 Socket,然后浏览器根据这个 URL 组装成一个 get 类型的 HTTP 请求,通过 outputStream.write 发送到目标服务器,服务器等待 inputStream.read 返回数据,最后断开这个连接。
所以 HTTP 连接本质上就是建立一个 Socket 连接。
不借助浏览器,是否能实现一个 HTTP 连接呢?
a. 在 Java 中,我们可以通过开源的 HttpClient 工具包
b. 在Linux 中,通过 curl + URL 可以简单的发起一个请求
2. HTTP 解析
B/S网络架构的核心是 HTTP,而要理解 HTTP,最重要的是要熟悉 HTTP Header,它控制着用户浏览器的渲染行为和服务器的执行逻辑。常见的 HTTP 请求头和响应头分别如表 1-1 和 1-2所示,常见的 HTTP 状态码如表 1-3所示。
要查看一个 HTTP 请求的请求头和响应头,可以通过浏览器插件,比如 Firefox 中 Firebug 和 HttpFox,Chrome浏览器自带的开发工具也可以看(F12打开)。个人Chrome 用的比较多,就以这个为例吧:
先F12打开Chrome 开发者模式,访问百度页面,如下就可以看到 www.baidu.com 的请求 header。
3. 浏览器缓存机制
在我们在浏览一个页面发现有异常时,通常考虑的就是是不是浏览器做了缓存,一般做法就是按 Ctrl + F5 组合键重新请求一次页面。a. 在浏览器端,如果使用 Ctrl + F5 刷新页面,那么浏览器会直接相目标 URL 发送请求,而不会使用浏览器缓存的数据;b. 其次,即使请求发送到服务端,也有可能访问到的是缓存的数据,比如在应用服务器前端部署一个缓存服务器(Varnish代理)。
使用 Ctrl + F5 刷新页面,会在 HTTP header中添加一些请求头:Pragma:no-cache 和 Cache-Control:no-cache,如下图:
Ctrl + F5 刷新之后:可以看到,header中部分参数已经改变了
A. Cache-Control/Pragma:用于指定所有缓存机制在整个请求/响应链中必须服从的指令。
Cache-Control:被各个浏览器支持的很好,而且优先级比较高,和其他请求字段(如 Expires)同时出现时,Cache-Control 会覆盖其他字段。 Pragma 作用和 Cache-Control 类似。
B. Expires:通常格式是:
C. Last-Modified/Etag:表示一个服务器上的资源的最后修改时间(资源可以是静态的,静态内容自动加上 Last-Modified字段,动态内容由Servlet提供一个getLastModified方法用于检查某个动态内容是否更新)。而Etag作用是让服务端给每个页面分配一个唯一的编号,然后通过编号区分当前页面是否是最新的。这个比 Last-Modified 更加灵活,但后端web服务器有多台时比较难处理,因为每个服务器都要记住网站的所有资源。