目录
前言
博主将用 CSDN 记录 Java 后端开发学习之路上的经验,并将自己整理的编程经验和知识分享出来,希望能帮助到有需要的小伙伴。
博主也希望和一直在坚持努力学习的小伙伴们共勉!唯有努力钻研,多思考勤动手,方能在编程道路上行至所向。
由于博主技术知识有限,博文中难免会有出错的地方,还望各位大佬包涵并批评指正,博主会及时改正;如果本文对小伙伴你有帮助的话,求求给博主一个赞支持一下,可以一起交流,一起加油!!
本文是博主在学习B站尚硅谷、黑马程序员等机构的JavaWeb网课时整理的学习笔记,在这里感谢各个机构的优质网课,如果有兴趣的小伙伴也可以去看看。
2.1 HTTP 简介
2.1.1 HTTP概念
Hyper Text Transfer Protocol
:超文本传输协议,规定了浏览器和服务器之间数据传输的规则。
- 数据传输的规则指的是请求数据和响应数据需要按照指定的格式进行传输。
- 如果想知道具体的格式,可以打开浏览器,点击
F12
打开开发者工具,点击Network
来查看某一次请求的请求数据和响应数据具体的格式内容,如下图所示:
注意:在浏览器中如果看不到上述内容,需要清除浏览器的浏览数据。
chrome
浏览器可以使用ctrl+shift+Del
进行清除。
所以学习HTTP 协议主要就是学习请求和响应数据的具体格式内容。
2.1.2 HTTP协议特点
HTTP协议有它自己的一些特点,分别是:
1. 基于TCP协议: 面向连接,安全。
- TCP是一种面向连接的(建立连接之前是需要经过三次握手)、可靠的、基于字节流的传输层通信协议,在数据传输方面更安全。
2. 基于请求-响应模型:一次请求对应一次响应。
- 请求和响应是一一对应关系
3. HTTP协议是无状态协议:对于业务处理没有记忆能力。即每次请求-响应都是独立的。
-
无状态指的是浏览器发送HTTP请求给服务器之后,服务器根据请求响应数据,响应完后,服务器不会记录任何数据信息。这种特性有优点也有缺点:
-
缺点:在同一个浏览器的多次请求间不能共享数据。
-
优点:速度快。
-
-
请求之间无法共享数据会引发的问题,如:
-
京东购物,加入购物车和去购物车结算是两次不同的请求。
-
由于HTTP 协议的无状态特性,服务器处理加入购物车的请求响应结束后,并未记录加入购物车是何商品。
-
浏览器发起去购物车结算的请求后,因为无法获取哪些商品已经加入了购物车,所以会导致此次请求无法正确展示数据。
-
具体使用的时候,我们发现京东是可以正常展示购物车数据的,原因是 Java早已考虑到这个问题,并提出了使用 会话技术(Cookie、Session
) 来解决这个问题。具体如何来做,我们后面会详细讲到。
刚才提到 HTTP 协议是规定了请求和响应的数据的格式,那具体的格式是什么呢?接着往下看。
2.2 请求报文的数据格式
2.2.1 格式介绍
请求报文的数据总共分为三部分内容,分别是请求行、请求头、请求体。如下图:
1. 请求行: HTTP请求中的第一行数据,请求行包含三块内容,分别是
- 请求的方式 (
POST/GET
),请求方式有七种,最常用的是GET
和POST
方式; - 请求的
URL
(资源地址); - 请求的协议版本(一般都是 HTTP1.1)
2. 请求头: 第二行开始,包含了很多浏览器需要告诉服务器的信息,比如:我的浏览器型号、版本、我能接收的内容的类型、我给你发的内容的类型、内容的长度等等。格式为key: value
形式。
- 请求头中会包含若干个属性,常见的 HTTP请求头有:
Host:表示请求的主机名
User-Agent: 浏览器版本,例如Chrome浏览器的标识类似 Mozilla/5.0,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...)like Gecko;
Accept:表示浏览器能接收的资源类型,如text/*,image/*或者 */*表示所有;
Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
Accept-Encoding:表示浏览器可以支持的压缩类型,例如gzip, deflate等。
这些数据有什么用处?
举例说明:服务器可以根据请求头中的内容来获取浏览器的相关信息,有了这些信息服务器就可以处理不同的业务需求,比如:
- 不同浏览器解析
HTML
和CSS
标签的结果会有不一致,所以就会导致相同的代码在不同的浏览器会出现不同的效果。 - 服务器根据浏览器请求头中的数据获取到浏览器的浏览器类型,就可以根据不同的浏览器设置不同的代码来达到一致的效果。
- 这就是我们常说的浏览器兼容问题。
3. 请求体,有三种形式:
- 请求方式为
GET
方式,则请求报文中没有请求体,看不到form data
,GET
请求的请求参数存储在请求行中,是紧跟着URL
后面的。 - 请求方式为
POST
方式,请求报文中有请求体,看的到form data
,POST
请求的请求参数存储在请求体的form data
中。 - 请求报文为
JSON
格式,请求报文中有请求体,为request payload
。
POST
请求的请求体,是用于存储请求参数的。如下图:
如上图红线框的内容就是请求体的内容,请求体和请求头之间是有一个空行隔开。此时浏览器发送的是POST
请求,为什么不能使用GET
呢?这时就需要回顾GET
和POST
两个请求之间的区别了:
GET
请求的请求参数存储在请求行中,没有请求体;POST
请求的请求参数存储在请求体中。GET
请求请求参数大小有限制;POST
没有限制。
2.2.2 小结
-
请求数据中包含三部分内容,分别是请求行、请求头和请求体。
-
POST
请求的数据存储在请求体中,GET
请求的数据存储在请求行上。
2.3 响应数据格式
2.3.1 格式介绍
响应数据总共分为三部分内容,分别是响应行、响应头、响应体。如下图:
1. 响应行:响应数据的第一行,响应行包含三块内容,分别是:
- 协议版本;
- 响应状态码(200/ 404/ 405 / 500…);
- 响应状态(正常响应/ 找不到资源/ 请求方式不支持/ 服务器内部错误…);
2. 响应头:第二行开始,格式为key:value
形式
-
包含了服务器的信息;
-
服务器发送给浏览器的信息(内容的媒体类型、编码、内容长度等);
-
响应头中会包含若干个属性,常见的 HTTP响应头有:
Content-Type:表示该响应内容的类型,例如text/html,image/jpeg;
Content-Length:表示该响应内容的长度(字节数);
Content-Encoding:表示该响应压缩算法,例如gzip;
Cache-Control:指示浏览器应如何缓存,例如max-age=300表示可以最多缓存300秒
3. 响应体:最后一部分。存放响应数据
- 上图中
<html>...</html>
这部分内容就是响应体,它和响应头之间有一个空行隔开。
2.3.2 响应状态码
1. 状态码大类分类如下表:
状态码分类 | 说明 |
---|---|
1xx | 响应中——临时状态码,表示请求已经接受,告诉浏览器应该继续请求或者如果它已经完成则忽略它 |
2xx | 成功——表示请求已经被成功接收,处理已完成 |
3xx | 重定向——重定向到其它地方:它让浏览器再发起一个请求以完成整个处理。 |
4xx | 浏览器错误——处理发生错误,责任在浏览器,如:浏览器的请求一个不存在的资源,浏览器未被授权,禁止访问等 |
5xx | 服务器端错误——处理发生错误,责任在服务器,如:服务器抛出异常,路由出错,HTTP版本不支持等 |
状态码大全:https://cloud.tencent.com/developer/chapter/13553
2. 常见的响应状态码
状态码 | 英文描述 | 解释 |
---|---|---|
200 | OK | 浏览器请求成功,即处理成功,这是我们最想看到的状态码 |
302 | Found | 指示所请求的资源已移动到由Location 响应头给定的 URL,浏览器会自动重新访问到这个页面 |
304 | Not Modified | 告诉浏览器,你请求的资源至上次取得后,服务器并未更改,你直接用你本地缓存吧。隐式重定向 |
400 | Bad Request | 浏览器请求有语法错误,不能被服务器所理解 |
403 | Forbidden | 服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源 |
404 | Not Found | 请求资源不存在,一般是URL输入有误,或者网站资源被删除了 |
428 | Precondition Required | 服务器要求有条件的请求,告诉浏览器要想访问该资源,必须携带特定的请求头 |
429 | Too Many Requests | 太多请求,可以限制浏览器请求某个资源的数量,配合 Retry-After(多长时间后可以请求)响应头一起使用 |
431 | Request Header Fields Too Large | 请求头太大,服务器不愿意处理请求,因为它的头部字段太大。请求可以在减少请求头域的大小后重新提交。 |
405 | Method Not Allowed | 请求方式有误,比如应该用GET请求方式的资源,用了POST |
500 | Internal Server Error | 服务器发生不可预期的错误。服务器出异常了,赶紧看日志去吧 |
503 | Service Unavailable | 服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好 |
511 | Network Authentication Required | 浏览器需要进行身份验证才能获得网络访问权限 |
关于响应状态码,我们先主要认识三个状态码,其余的等后期用到了再去掌握:
200 ok
:浏览器请求成功。404 Not Found
:请求资源不存在。500 Internal Server Error
:服务器发生不可预期的错误。
2.3.3 尝试自定义一个简单的服务器
我们可以自定义一个服务器代码,用于处理浏览器发送的请求,主要使用到的是ServerSocket
和Socket
类。(注:下面代码不用自己写,只是需要大家看一下即可)
代码如下:
import sun.misc.IOUtils;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
/*
自定义服务器
*/
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8080); // 监听指定端口
System.out.println("server is running...");
while (true){
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 {
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
BufferedWriter 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 {
// 发送成功响应:
//读取html文件,转换为字符串
BufferedReader br = new BufferedReader(new FileReader("http/html/a.html"));
StringBuilder data = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null){
data.append(line);
}
br.close();
int length = data.toString().getBytes(StandardCharsets.UTF_8).length;
writer.write("HTTP/1.1 200 OK\r\n");
writer.write("Connection: keep-alive\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.toString());
writer.flush();
}
}
}
上面代码,大家并不需要自己写。通过上述代码,只需要大家了解到服务器可以使用 Java 完成编写,是可以接受浏览器发送的请求并且响应数据给浏览器的。
以后我们真正用到的Web服务器,并不需要自己写代码,而都是直接使用目前比较流行的Web服务器,比如Tomcat。下一篇博文我们就会接着介绍Tomcat。
2.3.4 小结
-
响应报文的数据中包含三部分内容,分别是响应行、响应头和响应体。
-
掌握
200,404,500
这三个响应状态码所代表含义,分别是:访问成功、所访问的资源不存在、服务器发生不可预期的错误。