搜索 K
Appearance
博客正在加载中...
Appearance
在学习 JavaWeb 开发之前,我们简单回顾下网络相关的概念
目前软件架构主要分为 2 种:
在 BS 架构中,用户访问的资源可以分为两类:
举个例子,用户打开一个网站的登录页,所有用户的登录页都是一样的,所以登录页是一种静态资源,里面还包含了登录页的 HTML、CSS 和 JS 等静态资源;
用户登录后,每个用户的信息都是不同的,例如用户名不同,此时需要根据情况动态的展示网页,这样不同用户登录后,看到的东西才是不一样的,才是他们自己的。例如我登录自己的 B 站账号,显示的就是我的登录名
根据用户请求的资源不同,请求可以划分为动态请求和静态请求。
学习 JavaWeb 之前,读者应该对计算机网络有基本的概念,知道如下几个术语:
IP:电子设备(计算机)在网络中的唯一标识。
端口:应用程序在计算机中的唯一标识。 0~65536
传输协议:规定了数据传输的规则基础协议。例如两个人之间交流,使用的语言得一致,不然一个人说英文,一个人说中文,两者互相听不懂。基础的传输协议如下:
服务器:安装了服务器软件的计算机。例如邮件服务器、web 服务器,游戏服务器,MySQL 服务器等等
服务器软件:运行后监听某个端口,接收用户的请求,处理请求,做出响应。例如邮件进程,游戏进程,MySQL 进程等等。
Web 服务器软件:接收用户的 HTTP 请求,处理请求,做出响应。在 Web 服务器软件中,可以部署 Web 项目,让用户通过浏览器来访问这些项目。
之前我们说的动态资源,就得依赖于 Web 服务器去运行,因此 Web 服务器软件也叫 Web 容器。 HTTP 服务器本质上也是一种应用程序,绑定服务器的 IP 地址并监听某一个 TCP 端口来接收并处理 HTTP 请求,这样客户端(一般来说是 IE, Firefox,Chrome 这样的浏览器)就能够通过 HTTP 协议来获取服务器上的网页(HTML 格式)、文档(PDF 格式)、音频(MP4 格式)、视频(MOV 格式)等等资源。下图描述的就是这一过程:
我们来看一下如何编写 HTTP Server。一个 HTTP Server 本质上是一个 TCP 服务器,我们先用 TCP 编程 的多线程实现的服务器端框架:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8080); // 监听指定端口
System.out.println("server is running...");
for (;;) {
Socket sock = ss.accept();
System.out.println("connected from " + sock.getRemoteSocketAddress());
Thread t = new Handler(sock);
t.start();
}
}
}
class Handler extends Thread {
Socket sock;
public Handler(Socket sock) {
this.sock = sock;
}
public void run() {
try (InputStream input = this.sock.getInputStream()) {
try (OutputStream output = this.sock.getOutputStream()) {
handle(input, output);
}
} catch (Exception e) {
try {
this.sock.close();
} catch (IOException ioe) {
}
System.out.println("client disconnected.");
}
}
private void handle(InputStream input, OutputStream output) throws IOException {
var reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
// TODO: 处理HTTP请求
}
}只需要在 handle() 方法中,用 Reader 读取 HTTP 请求,用 Writer 发送 HTTP 响应,即可实现一个最简单的 HTTP 服务器。编写代码如下:
private void handle(InputStream input, OutputStream output) throws IOException {
System.out.println("Process new http request...");
var reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
var writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));
// 读取HTTP请求:
boolean requestOk = false;
String first = reader.readLine();
if (first.startsWith("GET / HTTP/1.")) {
requestOk = true;
}
for (;;) {
String header = reader.readLine();
if (header.isEmpty()) { // 读取到空行时, HTTP Header读取完毕
break;
}
System.out.println(header);
}
System.out.println(requestOk ? "Response OK" : "Response Error");
if (!requestOk) {
// 发送错误响应:
writer.write("HTTP/1.0 404 Not Found\r\n");
writer.write("Content-Length: 0\r\n");
writer.write("\r\n");
writer.flush();
} else {
// 发送成功响应:
String data = "<html><body><h1>Hello, world!</h1></body></html>";
int length = data.getBytes(StandardCharsets.UTF_8).length;
writer.write("HTTP/1.0 200 OK\r\n");
writer.write("Connection: close\r\n");
writer.write("Content-Type: text/html\r\n");
writer.write("Content-Length: " + length + "\r\n");
writer.write("\r\n"); // 空行标识Header和Body的分隔
writer.write(data);
writer.flush();
}
}这里的核心代码是,先读取 HTTP 请求,这里我们只处理 GET / 的请求。当读取到空行时,表示已读到连续两个 \r\n,说明请求结束,可以发送响应。
发送响应的时候,首先发送响应代码 HTTP/1.0 200 OK 表示一个成功的 200 响应,使用 HTTP/1.0 协议,然后,依次发送 Header,发送完 Header 后,再发送一个空行标识 Header 结束,紧接着发送 HTTP Body,在浏览器输入 http://localhost:8080/ 就可以看到响应页面:
可以看到编写一个简单的 HTTP 服务器并不难,只需要先编写基于多线程的 TCP 服务,然后在一个 TCP 连接中读取 HTTP 请求,发送 HTTP 响应即可。
但是,要编写一个完善的 HTTP 服务器,以 HTTP/1.1 为例,需要考虑的包括:
这些基础工作需要耗费大量的时间,并且经过长期测试才能稳定运行。如果我们只需要输出一个简单的 HTML 页面,就不得不编写上千行底层代码,那就根本无法做到高效而可靠地开发。
因此,在 JavaEE 平台上,处理 TCP 连接,解析 HTTP 协议这些底层工作统统扔给现成的 Web 服务器去做,我们只需要把自己的应用程序跑在 Web 服务器上。
开源且常见的:
Nginx:一款自由开源的、高性能的 HTTP 服务器和反向代理服务器,使用率较高。
Tengine:Tengine 是阿里巴巴在 Nginx 的基础上,添加了很多高级功能和特性改造而成,做了一定的优化
Tomcat:归属于 Apache 基金组织,中小型的 JavaEE 服务器,开源免费。
Apache:非常老牌的 WEB 服务器,稳定、开源、跨平台,性能较 Nginx 低
Lighttpd:开源,CPU 占用率低,内存开销小,也有不少人使用 商业级且常见的:
WebShare:通常简称 WAS,IBM 公司开发的,大型的 JavaEE 服务器,支持所有的 JavaEE 规范,收费的。
WebLogic:Oracle 公司开发的,大型的 JavaEE 服务器,支持所有的 JavaEE 规范,收费的。
JBOSS 公司的,大型的 JavaEE 服务器,支持所有的 JavaEE 规范,收费的。
一般来说商业级的都是重量级的,安装包大、功能强大且繁多。一般得专人支持才能使用,因为是商业级的东西,网上也比较少入门的资料,毕竟是付费产品,如果想要自己学习的话比较难,因为文档资料不会公开,想要安装的话还得购买许可证,门槛高。
Apache 和 Nginx 本身不支持生成动态页面(不提供动态资源),但它们可以通过其他模块来支持(例如通过 Shell、PHP、Python 脚本程序来动态生成内容)。
如果想要使用 Java 程序来动态生成资源内容,使用这一类 HTTP 服务器很难做到。Java Servlet 技术以及衍生的 Java Server Pages 技术可以让 Java 程序也具有处理 HTTP 请求并且返回内容(由程序动态控制)的能力,Tomcat 正是支持运行 Servlet/JSP 应用程序的容器(Container)。后续我们就学习 JavaWeb 技术,使得 Java 可以开发一个网站并且发布。
本系列主要使用 Nginx 和 Tomcat 用于学习 JavaWeb 开发,这两个也是目前使用率比较高的。