文章目录
- JavaWeb之HTTP学习
- 1、HTTP相关基本概念
- 2、数据格式介绍
- 2.1 请求的数据格式
- 2.2 响应的数据格式
- 案例
JavaWeb之HTTP学习
1、HTTP相关基本概念
-
什么是HTTP?
HTTP(HyperText Transfer Protocol,超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
其主要作用是用于客户端和服务端的通信的规范,即:
- 请求:客户端应该发送什么样的请求数据给服务端,规定请求的形式
- 响应:服务端收到客服端的请求数据应该做出什么样的响应,规定响应的形式
HTTP好比是一座桥梁,用于连接客户端和服务端。类比生活中的事情,当我们要和外国人交流,不可能你说中文、他说日语,这就会导致沟通障碍(当然这个例子也不太恰当,因为有些人可能两种语言都懂),为了方便交流我们就会选择一种语言当作中间语言,而这个中间语言就好比HTTP,中国人和外国人就好比客户端和服务端。
学习HTTP主要就是学习请求和响应数据的具体格式内容。
-
HTTP的特点:
1)安全可靠。因为HTTP协议是基于TCP协议的
2)一次请求对应一次响应。因为HTTP是基于请求-响应模型的
3)对事物的处理没有记忆能力。因为HTTP协议是无状态1协议,对于每次事物的处理都是独立的,所以对事物的处理没有记忆能力
-
HTTP的优点和缺点:
1)优点:
①灵活性高,扩展性强。每当应用程序需要其他功能时,HTTP都可以下载扩展或插件并显示相关数据
②可靠传输。HTTP是基于TCP协议的
③数据传输快。第一,HTTP对事物处理没有记忆能力,无需在意之前请求和响应的数据;第二,只有当连接建立时,握手过程才会发生在HTTP中。因此,请求之后不会有握手过程。这显着减少了连接中的延迟
2)缺点:
①明文传输不安全。使用HTTP进行明文传输数据,很容易被人通过抓包获取数据
②无法复用同一TCP连接。复用同一个TCP连接会导致队头阻塞2
③多次请求之间的数据无法共享。因为HTTP对事物的处理没有记忆能力,每一次请求-响应都是独立的。(但是Java早已想到了这个问题,所以提出了会话技术
Cookie
、Session
来解决这个问题Java就是碟)
2、数据格式介绍
2.1 请求的数据格式
-
请求数据的组成:
请求行+请求头+[请求体]
1)请求行:位于请求数据的第一行,格式为:
请求方式 /请求的资源路径 协议名称/协议版本号
。HTTP的请求方式共有七种3,常见的有两种,分别是GET
请求和POST请求
2)请求头:从第二行开始,格式为:
key: value
常见的请求头:
Host
: 表示请求的主机名Connection
: 请求连接的方式。一般默认是keep-alive,表示请求建立长连接User-Agent
: 表示浏览器的版本。例如Chrome浏览器的标识类似Mozilla/5.0 …Chrome/79,IE浏览器的标识类似Mozilla/5.0(Windows NT …)like GeckoAccept
:表示浏览器能接收的资源类型。如text/,image/或者*/*表示所有Accept-Language
:表示浏览器偏好的语言。服务器可以据此返回不同语言的网页Accept-Encoding
:表示浏览器可以支持的压缩类型。例如gzip, deflate等
3)请求体:位于最后一行,用于存放请求参数,GET请求不具有,格式:
key=value&...
-
GET请求和POST请求的区别
1)请求参数存放位置不同。GET请求没有请求体,请求参数存放在请求行中;而POST请求具有,请求参数存放再请求体中
2)请求参数的限制不同。GET请求请求参数大小有限制,POST没有
2.2 响应的数据格式
-
响应数据的组成:
响应行+响应头+响应体
1)响应行:位于响应数据的第一行,格式为:
协议名称/协议版本号 响应码 状态码
常见响应码(1xx~5xx):
状态码分类 说明 1xx 响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它 2xx 成功——表示请求已经被成功接收,处理已完成 3xx 重定向——重定向到其它地方:它让客户端再发起一个请求以完成整个处理。 4xx 客户端错误——处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等 5xx 服务器端错误——处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等 200 ok
:客户端请求成功400
:服务端无法识别请求(一般是客户端请求的数据存在语法错误)404 Not Found
:请求资源不存在(一般是URL错误,或者资源被移除)500 Internal Server Error
:服务端发生不可预期的错误(一般是Java代码出现异常,建议去看日志文件)
状态码大全:HTTP中文开发手册
推荐阅读:Http响应码分类汇总
2)响应头:从第二行开始,格式为:
key: value
常见的响应头:
Server
:表示服务器以及服务器的版本号,例如:Tengine/1.4Content-Type
:表示该响应内容的类型,例如:text/html,image/jpegContent-Length
:表示该响应内容的长度(字节数)Content-Encoding
:表示该响应压缩算法,例如gzipCache-Control
:指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒
3)响应体:是响应数据的最后一部分,用于存放响应后的数据,是html格式
案例
模拟客户端访问服务端,服务端给发送请求数据
pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hhxy</groupId>
<artifactId>day5_http</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
Java代码:
package com.hhxy.http;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
/*
自定义服务器
*/
public class Server {
public static void main(String[] args) throws IOException {
//1、获取ServerSocket对象,注册端口号
ServerSocket ss = new ServerSocket(8080); // 监听指定端口
System.out.println("server is running...");//测试代码
//2、重复接收客户端发送的信息
while (true){
//3、于客户端建立Socket管道连接
Socket sock = ss.accept();
//测试代码,获取远程客户端的IP地址
System.out.println("connected from " + sock.getRemoteSocketAddress());
//4、创建线程,并执行任务
Thread t = new Handler(sock);
t.start();
}
}
}
/**
* 线程类
*/
class Handler extends Thread {
Socket sock;//服务端每次接收的来自不同客户端Socket对象
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.");
}
}
/**
* 线程类的核心方法:用于服务端处理HTTP请求数据,以及向客户端发送响应数据
* @param input
* @param output
* @throws IOException
*/
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("html/hello.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();
}
}
}
无状态指的是客户端发送HTTP请求给服务端之后,服务端根据请求响应数据,响应完后,不会记录任何信息 ↩︎
队头阻塞简而言之,就是如果一个响应返回延迟了,那么其后续的响应都会被延迟,直到队头的响应送达 ↩︎
七种方式,分别为:GET方法、POST方法、HEAD方法、PUT方法、DELETE方法、CONNECT方法、OPTIONS方法、TRACE方法 ↩︎