深入分析Java Web技术内幕读书笔记(一)浅析Web请求过程

随着Web技术的快速发展,互联网的网络架构已经从传统的C/S架构转变为B/S架构,B/S架构相较于传统的C/S架构,有诸多优点,例如:提供了统一的操作方式,简化了用户的学习成本;便捷的开发方式大大提高了开发者的开发效率;遵循统一的HTTP请求协议,开发运营维护十分方便。

一、B/S网络架构简单概述

B/S网络架构采用的是统一的应用层协议HTTP来进行数据的交互,与传统的C/S应用采用的长连接交互方式不同,B/S应用是无状态的短连接的通信方式。也就是说,一次请求对应一次响应,响应结束后,本次通信也就结束了,这种方式可以满足大数据量的用户的访问需求,节约了物理资源。
我们最常见的操作就是在浏览器的地址栏输入一个网络地址,敲击回车键即可在浏览器容器上看到服务器返回来的内容,但是,在敲击回车键之后,客户端到服务端都具体完成了哪些操作,才能将数据以最美的状态呈现在我们的面前,这个也是需要了解一下的。
CDN架构图
根据上图来简单解释一下当用户输入完网络地址和敲击回车键之后,浏览器和服务器都做了些什么动作:

  • 当用户在浏览器的地址栏输入了www.csdn.net之后,首先浏览器将请求DNS服务器,请求DNS服务器解析当前URL,匹配当前URL对应的实际IP地址,当配到IP地址,浏览器向这个IP地址发送get请求,远程服务器接收到请求之后,将用户需要的数据返回给用户。

  • 在实际的服务端,往往伴随着很多复杂的业务逻辑,服务器有很多台,但是具体有哪一台服务器来提供服务,往往是由负载均衡设备来均衡分配。还有一点就是用户请求的数据也许是一个文件,那么服务器就需要访问文件系统,获取指定文件,也许用户需要的资源在缓存系统中已经缓存了,那么服务器优先访问缓存文件,也许用户需要的数据直接存储在数据库中,那么服务器就需要访问数据库系统,获取数据。

  • 当浏览器接收到服务器返回的数据后,解析发现有许多静态资源是存储在CDN上,那么将再次向CDN服务器发送HTTP请求,那么CDN又将会处理这些请求,流程和上面的类似。至于这里面的更多细节,都会影响最终的数据完整返回。

那么对于一个完整的B/S应用,不管网络架构如何变化,它应该始终需要遵循一些基本原则:

  • 每一个资源存在互联网的某一个角落,访问该资源,需要使用唯一的一个URL来描述其位置;

  • 资源的访问与交互都需要基于HTTP协议,这样才可以与远程服务器正确地打招呼;

  • 需要使用浏览器来还原数据,客户端拿到数据以后,数据的展示一般都需要浏览器来进行渲染还原。

二、如何发起一个请求

发起HTTP请求最常见的方式就是在浏览器地址栏输入URL,敲击回车键就发起了一个HTTP请求,比如在地址栏输入www.csdn.net,敲击回车键之后很快浏览器就接收到了服务器返回的数据并渲染完毕,以最佳的方式将数据还原,这是一种最基本的发起请求的方式。还有稍微复杂一点的方式,那就是自己组装HTTP请求头和请求体,也可以实现脱离浏览器发起HTTP请求。对于发起HTTP请求,其实和服务器建立Socket连接区别不大,只不过outputStream.write方法输出的二进制数据格式要符合HTTP规范。在浏览器和服务器建立Socket连接之前,必须要执行的一个动作就是解析URL的域名,获取域名对应的IP地址,在根据这个地址和默认的80端口建立起Socket连接,然后在获取URL中的参数组成一个get请求,使用outputStream.write方法发送到目标服务器,服务器等待inputStream.read方法读入参数并执行处理逻辑,然后返回数据后断开连接。
对于复杂一点的HTTP请求,我们完全可以根据HTTP的规范来自己组装请求头和请求体,从而实现模仿浏览器发起请求。下面的代码是借助hutool工具包来发起一个post请求。

private String post(HeaderModel headerModel, Object params) {
    return HttpRequest.post("http://" + headerModel.getHost() + headerModel.getRestfulUrl())
            .header("Method", headerModel.getMethod())
            .header("URL", headerModel.getRestfulUrl())
            .header("Host", headerModel.getHost())
            .header("Content-Type", headerModel.getContentType())
            .header("Content-Length", headerModel.getContentLength())
            .body(JSONUtil.parse(params)).execute().body();
}

这里是我在项目中封装了一个私有方法,传入的参数是请求头模型和参数模型,请求头模型中可以提供host,RESTful API,method等信息,请求参数体直接通过JSONUtil转换为json字符串,然后直接发起post请求。当然,这里使用的是hutool工具包的发起请求的方法,还有较为出名的HttpClient也可以做到从代码层面处理HTTP请求。
在linux系统中,还可以通过命令行来发起请求,例如curl “https://www.baidu.com“,可以返回百度首页页面的HTML数据,由于不是使用浏览器发起的请求,所以这些数据无法正常解析从而展示百度首页。当然linux中还有wget命令可以实现发起文件下载的请求,可以轻松轻松从互联网下载文件。
这里写图片描述

扫描二维码关注公众号,回复: 2494525 查看本文章

猜你喜欢

转载自blog.csdn.net/Lammonpeter/article/details/81254747