Web运作原理简介
2023-12-18 21:59:11 # 技术

0x00 Web的概念

Web是一种分布式应用架构,旨在共享分布在网络上的各个Web服务器中的所有互相链接的信息。Web采用客户/服务器模式,客户与服务器之间用HTTP协议通信。Web使用超文本标记语言 (HTML)来链接网络上的信息。信息存放在服务器端,客户机通过浏览器就可以查找网络中的各个Web服务器上的信息。

Web的特征:

  • 信息的表达:用超级文本技术HTML来表达信息,以及建立信息与信息的链接。
  • 信息的定位:用统一资源定位技术URL来实现网络上信息的精确定位。
  • 信息的传输:用网络应用层协议HTTP来规范浏览器与Web服务器之间的通信过程。

注:Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件反馈到该浏览器上,附带的信息会高速浏览器如何查看该文件(即文件类型)。服务器使用HTTP(超文本传输协议)与客户机浏览器进行信息交流,因此也常被称为HTTP服务器

0x10 HTML简介

HTML(Hyper Text Markup Language)即超文本标记语言。用HTML语言编写的文档,即HTML文档,它不仅可以直接包含文本内容,还可以把其他形式的信息包含进来。其特点如下:

  • 允许直接包含纯文本形式的信息。
  • 利用<img><embed>等标记来包含图片和声音等多媒体形式的信息。
  • 利用<p><br><font>等标记来设定信息在浏览器中的展示格式。
  • 利用超级链接<a<来链接到其他信息。

浏览器能够解析HTML文档中的标记,并且可以在浏览器窗口中直观的展示HTML文档。人们通常所说的网页或者Web页面,就是指HTML文档在浏览器中的展示页面。

0x20 URL简介

URLUniform Resource Locator的缩写,表示统一资源定位器,它是专门为标识网络上的资源位置而设的一种编址方式。URL一般由三个部分组成:

  • 应用层协议
  • 主机IP地址或域名
  • 资源所在路径/文件名

URL 的格式:应用层协议://主机IP地址或域名/路径/文件名

0x30 HTTP协议简介

略。

0x40 用Java套接字创建HTTP客户与服务器程序

当用户在浏览器中输入一个指向特定网页的URL时,浏览器会通过DNS解析域名,根据域名解析出服务器的IP地址后,浏览器会向这个IP地址发送请求,建立与远程服务器的TCP连接,然后浏览器将生成的HTTP请求发送给远程服务器,服务器再返回包含响应网页数据的HTTP响应,最后浏览器会把这个网页显示出来。

浏览器应该具备的功能:

  • 请求与Web服务器建立TCP连接
  • 创建并发送HTTP请求
  • 接收并解析HTTP响应
  • 在窗口展示HTTP文档

Web服务器应该具备的功能:

  • 接收来自浏览器的TCP连接请求
  • 接收并解析HTTP请求
  • 创建并发送HTTP响应

HTTP客户程序和HTTP服务器分别由不同的软件开发商开发,目前最常用的HTTP客户程序包括Firefox、Chrome等,在Unix和Linux平台下使用最广泛的免费HTTP服务器是Apache和Nginx服务器,而Windows平台使用IIS服务器。HTTP客户程序和服务器程序都可以用任意的编程语言编写,并且可以运行在不同的平台上,其顺利通信归功于HTTP协议。HTTP协议严格规定了HTTP请求和HTTP响应的数据格式,只要HTTP服务器与客户程序之间的交换数据都遵守HTTP协议,双方就能看得懂对方发送的数据,从而顺利交流。

HTTP服务器的简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpServer {
public static void main(String[] args){
int port = 8090;
ServerSocket serverSocket;
try{
/*
服务器监听端口
*/
serverSocket = new ServerSocket(port);
System.out.println("服务器正在监听端口:" + serverSocket.getLocalPort());
while(true){

Socket socket = serverSocket.accept();
System.out.println("与客户端建立了一个TCP连接,客户端地址为:" + socket.getInetAddress());
// 调用service 方法解析HTTP请求
service(socket);

}

}
catch (Exception e)
{
e.printStackTrace();
}
}

public static void service(Socket socket) throws Exception{
// 获取来自客户端(浏览器)的输入流
InputStream socketIs = socket.getInputStream();

// 睡眠500毫秒来等待HTTP请求
Thread.sleep(500);

try{
/*
从输入流中读取HTTP请求
*/
int sizeIs = socketIs.available();
byte[] buffer = new byte[sizeIs];
socketIs.read(buffer);
String request = new String(buffer);
// 打印HTTP请求信息
System.out.println(request);


/*
解析HTTP请求
*/

// 获得Http请求的第一行
String firstLineOfRequest = request.substring(0, request.indexOf("\r\n"));
// 解析HTTP请求的第一行
String[] parts = firstLineOfRequest.split(" ");
String uri = parts[1]; // 获得请求URI

/*
决定HTTP响应正文的类型;
这里做简化处理,仅考虑两种类型;
*/
String contentType;
if(uri.indexOf("html") != -1 || uri.indexOf("htm") != -1)
contentType = "text/html";
else if(uri.indexOf("jpg") != -1 || uri.indexOf("jpeg") != -1)
contentType = "image/jpeg";
else
contentType = "application/octet-stream"; // 字节流类型

/*
创建响应HTTP响应结果
*/
// HTTP响应的第一行
String responseFirstLine = "HTTP1.1 200 OK\r\n";
// HTTP响应头
String responseHeader = "Content-Type:" + contentType + "\r\n\r\n"; // 注意响应头和正文之间有一个空行
// 根据请求URI获取响应正文数据的输入流
System.out.println(uri);
InputStream is = new FileInputStream("JavaWeb/WEB-INFO/" + uri);

/*
发送HTTP响应结果
*/
// 获得套接字的输出流
OutputStream socketOs = socket.getOutputStream();
// 发送HTTP响应的第一行
socketOs.write(responseFirstLine.getBytes());
// 发送HTTP响应头
socketOs.write(responseHeader.getBytes());
// 发送HTTP响应正文
int len = 0;
buffer = new byte[128];
while( (len = is.read(buffer)) != -1){
socketOs.write(buffer, 0, len);
System.out.println(new String(buffer));
}

System.out.println("发送完成");
Thread.sleep(1000);
socket.close();
}
catch (Exception e){

}
}
}

HTTP客户端的简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class HttpClient {
public static void main(String[] args){
String uri = "index.html";
doGet("127.0.0.1", 8090, uri);
}
public static void doGet(String host, int port, String uri){
Socket socket = null;
try{
// 与HTTP服务器建立TCP连接
socket = new Socket(host, port);
}
catch (Exception e){
e.printStackTrace();

}
try{
/*
构造HTTP请求头
*/
StringBuffer sb = new StringBuffer("GET " + uri + " HTTP/1.1\r\n");
sb.append("Accept: */*\r\n");
sb.append("Accept-Language: zh-cn\r\n");
sb.append("Accept-Encoding: gzip, deflate\r\n");
sb.append("User-Agent: HttpClient\r\n");

/*
发送HTTP请求
*/
OutputStream socketOs = socket.getOutputStream();
socketOs.write(sb.toString().getBytes());

// 睡眠2秒,等待HTTP响应
Thread.sleep(2000);
/*
接收HTTP响应并打印出响应结果
*/
InputStream socketIs = socket.getInputStream(); // 获得输入流
int size = socketIs.available();
byte[] buffer = new byte[size];
socketIs.read(buffer);
System.out.println(new String(buffer)); // 打印响应结果

}
catch (Exception e){
e.printStackTrace();
}
finally {
try{
socket.close(); // 断开TCP连接
}
catch (Exception e){
e.printStackTrace();
}
}
}
}

0x41 用HttpClient客户程序访问HttpServer程序

  1. 运行HttpServer程序,监听8090端口

    image.png
  2. 运行HttpClient程序,与HttpServer的8090端口建立TCP连接,发送一个HTTP请求,收到一个HTTP响应

    image.png
  3. 查看HttpServer的响应,HttpServer与HttpClient成功建立TCP连接,接收并解析来自HttpClient的HTTP请求并返回一个HTTP响应

    image.png

0x42 浏览器访问HttpServer程序

  1. 运行HttpServer程序,监听8090端口

    image.png
  2. 浏览器访问HttpServer程序,与HttpServer建立TCP连接并发送HTTP请求,收到HTTP响应并解析显示在浏览器窗口

    image.png
  3. HttpServer程序与浏览器建立TCP连接,接收其HTTP请求并返回一个HTTP响应

    image.png

0x50 Web的发展历程

0x51 阶段一:发布静态HTML文档

静态HTML文档就是指事先存放在Web服务器端的文件系统中的HTML文档。当用户在浏览器中输入指向特定HTML文档的URL时,WEB服务器就会把该HTML文档的数据发送到浏览器端。在这个阶段,HTML文档只能包含文本及图片。

未命名文件.png

0x52 阶段二:发布静态多媒体信息

在上一个阶段,信息只能以文本和图片的形式来发布,这满足不了用户对信息形式多样化的强烈需求。用户的需求使得多媒体信息被引入到Web领域,在这个阶段,信息可以用文本、图片、动画、声音和视频等形式来表示。

从技术角度来看,这个阶段主要增强了浏览器的功能,要求浏览器能集成一些插件,并利用这些插件来展示特定形式的信息;而Web服务器并不需要做改进,不管是任何形式的静态信息,它们都作为文件事先存放在Web服务器端的文件系统中,Web服务器只需把包含特定信息的文件中的数据发送给浏览器即可,然后由浏览器来负责解析和展示数据。

0x53 阶段三:提供浏览器端与用户的动态交互功能

在上述几个阶段,用户在浏览器端都只能被动的观看来自服务器的静态信息。到了本阶段,用户不仅可以通过浏览器浏览信息,还可以与浏览器交互。该功能的实现归功于Java AppletJavaScript等脚本语言的问世,此外,浏览器还必须能够解析和运行用脚本语言编写的小程序。

在这个阶段,Web服务器不需要做改进,执行用脚本语言编写的小程序的任务由浏览器来完成,Web服务器只要把包含小程序代码的文件中的数据发送到浏览器端即可。

0x54 阶段四:提供服务器端与用户的动态交互功能

以上第三个阶段为用户提供了一些动态交互功能,该功能是由浏览器来完成的,并对用户的浏览器提出了诸多技术要求,如果浏览器不支持某种脚本语言,就无法运行网页中的脚本程序。

可以说,以上三个阶段的技术发展点都是在客户端,而对Web服务器端都没有做特别要求。到了本阶段,Web服务器端增加了动态执行特定程序代码的功能,这使得Web服务器能利用特定程序代码来动态生成HTML文档。Web服务器动态执行的程序分为两种:

  • 完全用编程语言编写的程序,如CGI(Common Gateway Interface)程序和用Java编写的Servlet程序。
  • 嵌入了程序代码的HTML文档,如PHP、ASP和JSP文档。JSP文档是指嵌入了Java程序代码的HTML文档。

注:Web服务器动态执行特定程序代码的特征是Web服务器在运行时加载并执行由第三方提供的程序代码。所谓Web服务器动态生成HTML文档,就是指Web服务器再运行时才通过执行特定程序代码来生成HTML文档,而不是直接从文件系统中获取已经存在的HTML文档。

Servlet的简单模拟

下面以Servlet为例,简单介绍Web服务器动态执行完全用编程语言编写的程序的原理。

我们在服务器端存放一个用Java语言编写的程序的.class文件——HelloServlet.class。当用户在浏览器端输入指向该类的URL时,Web服务器就会运行HelloServlet类,HelloServlet类生成HTML文档,并把它发给浏览器。

image

我们首先定义了一个Servlet接口(这个Servlet接口与SUN公司的Servlet规范中的Servlet接口有相似之处,这个简化了的Servlet接口能帮助我们理解Servlet的作用和运行原理),这个接口有一个init()方法和service()方法:

  • init()方法:初始化方法,当HttpServerOne类创建了该接口的实现类的一个实例后,就会立即调用该实例的init()方法
  • service()方法:用于响应HTTP请求,产生具体的HTTP响应结果。HttpServerOne服务器在响应HTTP请求时,会调用实现了Servlet接口的特定类的service()方法。

所谓的Web服务器动态执行程序代码,在本范例中就是HttpServerOne在运行时动态加载Servlet接口的实现类,创建它的实例,然后调用它的相关方法,这利用了Java语言的动态加载类的功能。

HelloServlet类实现了Servlet接口,其service()方法能解析HTTP请求中的请求参数,并会根据请求参数username的取值来生成HTML文档。

下面我们运行HttpServerOne服务器,然后用浏览器访问:

  1. 启动服务器,监听端口

    image

  2. 浏览器访问,指定请求参数,得到对应的响应

    image

    在上面的HelloServlet类中我们必须费劲的解析原始的字符串形式的HTTP请求,而真正的Servlet技术无需我们自己动手解析字符串形式的HTTP请求,这个繁琐的工作由Servlet容器代劳了。

0x55 发布Web应用

本阶段是在上一个阶段的基础上发展起来的。Web服务器端可动态执行的程序的功能变得越来越强大,不仅能动态生成HTML文档,还能处理各种应用领域里的业务逻辑,还能访问数据库。在这个阶段出现了Web应用的概念。所谓的Web应用,是指需要通过编程来创建的Web站点。在Web应用中不仅包括普通的静态HTML文档,还包含大量可被Web服务器动态执行的程序。用户在Internet上能开展业务的各种Web站点都可看作Web应用。

Web应用与传统桌面应用程序相比,具有以下特点:

  • 以浏览器作为展示客户端界面的窗口
  • 客户端界面一律表现为网页形式,网页由HTML语言写成,具有交互功能
  • 能完成与桌面应用程序类似的功能
  • 使用浏览器-服务器架构,浏览器与服务器之间采用HTTP协议通信
  • Web应用通过Web服务器来发布

0x56 发布Web服务

Web是基于HTTP协议的分布式架构。HTTP协议采用客户/服务器通信模式,该协议规定了服务器与浏览器之间的交换数据的通信细节。

Web服务架构与Web一样,也是网络应用层的一种分布式架构,同时也是基于客户/服务器通信模式,并且也能实现异构系统之间的通信。在Web服务架构中,服务端负责提供Web服务,而客户端则请求Web服务。Web服务可以看做是被客户端远程调用的各种方法,这些方法能处理特定业务逻辑,或者进行复杂运算等。请求过程如下;

未命名文件 (2)

Web服务架构采用SOAP(Simple Object Access Protocol,简单对象访问协议)作为通信协议。SOAP协议规定客户与服务器之间一律用XML语言进行通信。XML(Extensible Markup Language,可扩展标记语言)是一种可扩展的跨平台的标记语言。SOAP协议规定了客户端向服务器端发送的Web服务请求的具体数据格式,以及服务器端向客户端发送的Web服务响应结果的具体数据格式。

Web服务实际上是借助Web服务器来发布到网络上的,借用Web服务器来发布Web服务,就不必再创建专门的基于SOAP协议的服务器程序了。以下是客户程序访问特定Web服务的过程:

  1. 客户程序发出一个原始请求
  2. 客户端协议解析器负责把客户程序的原始请求包装为一个XML格式的SOAP请求。SOAP请求是基于SOAP协议的Web服务请求的简称。
  3. 客户端协议连接器把SOAP请求包装成一个HTTP请求,其中SOAP请求变成了HTTP请求的正文部分。客户端协议连接器接着把HTTP请求发送给Web服务器。
  4. Web服务器接收到HTTP请求,取出HTTP请求的正文部分,即获得了SOAP请求
  5. 服务器端协议解析器从SOAP请求中获取客户程序的原始请求数据,对其解析,然后调用Web服务。
  6. Web服务返回原始的响应结果
  7. 服务器端协议解析器把Web服务返回的原始响应结果包装为SOAP响应结果。SOAP响应结果是基于SOAP协议的Web服务响应结果的简称。
  8. Web服务器把SOAP响应结果包装成一个HTTP响应结果,其中SOAP响应结果变成了HTTP响应结果的正文部分。Web服务器接着把HTTP响应结果发送给客户端协议连接器。
  9. 客户端协议连接器接收到HTTP响应结果,取出HTTP响应结果的正文部分,即得到了SOAP响应结果
  10. 客户端协议解析器从SOAP响应结果中得到Web服务的原始响应结果,把它交给客户程序。

Web的基本功能是提供客户程序与服务器之间的数据传输(主要是服务器发送给浏览器的HTML文档),而Web服务的基本功能是客户程序远程调用服务器端的方法。由于在进行远程方法调用时,客户端与服务器之间也涉及到数据的交换,因此Web服务可以借助Web来传输双方的通信数据。