一、HTTP协议-概述
-
在浏览器输入地址后,浏览器默认会自动在请求路径前面加上一个协议:HTTP
-
概念:
H
yperT
extT
ransferP
rotocol(超文本传输协议),规定了浏览器和服务器之间数据传输的规则。 -
HTTP:是数据传输的规则、格式:
- 分别是请求和响应数据的格式。
-
特点:
-
基于TCP协议:面向连接,安全
-
基于请求-响应模型的:一次请求对应一次响应
-
HTTP协议是无状态的协议:对于事务处理没有记忆能力。
-
无状态:每一次请求、响应都是独立的;后一次请求是不会记录前一次请求数据的。
-
缺点:多次请求间不能共享数据。
-
优点:速度快
-
-
二、HTTP协议-请求协议
1. 数据含义
Host | 请求的主机名 |
User-Agent | 浏览器版本,例如Chrome浏览器的标识类似Mozilla/5.0 … Chrome/79, IE浏览器的标识类似Mozilla/5.0 (Windows NT …) like Gecko |
Accept | 表示浏览器能接收的资源类型,如text/*,image/或者/*表示所有; |
Accept-Language | 表示浏览器偏好的语言,服务器可以据此返回不同语言的网页; |
Accept-Encoding | 表示浏览器可以支持的压缩类型,例如gzip, deflate等。 |
Content-Type | 请求主体的数据类型。 |
Content-Length | 请求主体的大小(单位:字节)。 |
2. GET和POST的区别
-
01.GET-POST.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>请求方式演示-GET-POST</title> </head> <body> <form action="" method="get"> 姓 名: <input type="text" name="name"> <br> 密 码: <input type="password" name="password"> <br> <input type="submit" value="提交(GET)"> </form> <br><br> <form action="" method="post"> 姓 名: <input type="text" name="name"> <br> 密 码: <input type="password" name="password"> <br> <input type="submit" value="提交(POST)"> </form> </body> </html>
(1)请求方式-GET
-
请求参数在请求行中,没有请求体,如:/brand/findAll?name=OPPO&status=1。GET请求大小是有限制的。
(2)请求方式-POST
- 请求参数在请求体中,POST请求大小是没有限制的。
三、HTTP协议-响应协议
1. 数据含义
2. 状态码
状态码分类 | 说明 |
---|---|
1xx | 响应中——临时状态码,表示请求已经接受,告诉客户端应该继续请求或者如果它已经完成则忽略它 |
2xx | 成功——表示请求已经被成功接收,处理已完成 |
3xx | 重定向——重定向到其它地方:它让客户端再发起一个请求以完成整个处理。 |
4xx | 客户端错误——处理发生错误,责任在客户端,如:客户端的请求一个不存在的资源,客户端未被授权,禁止访问等 |
5xx | 服务器端错误——处理发生错误,责任在服务端,如:服务端抛出异常,路由出错,HTTP版本不支持等 |
3.常见响应头
响应头 | 说明 |
---|---|
Content-Type | 表示该响应内容的类型,例如text/html,application/json。 |
Content-Length | 表示该响应内容的长度(字节数)。 |
Content-Encoding | 表示该响应压缩算法,例如gzip。 |
Cache-Control | 指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒。 |
Set-Cookie | 告诉浏览器为当前页面所在的域设置cookie。 |
4.常见的响应状态码
状态码 | 英文描述 | 解释 |
---|---|---|
200 | OK | 客户端请求成功,即处理成功,这是我们最想看到的状态码 |
302 | Found | 指示所请求的资源已移动到由Location 响应头给定的 URL,浏览器会自动重新访问到这个页面 |
304 | Not Modified | 告诉客户端,你请求的资源至上次取得后,服务端并未更改,你直接用你本地缓存吧。隐式重定向 |
400 | Bad Request | 客户端请求有语法错误,不能被服务器所理解 |
403 | Forbidden | 服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源 |
404 | Not Found | 请求资源不存在,一般是URL输入有误,或者网站资源被删除了 |
405 | Method Not Allowed | 请求方式有误,比如应该用GET请求方式的资源,用了POST |
428 | Precondition Required | 服务器要求有条件的请求,告诉客户端要想访问该资源,必须携带特定的请求头 |
429 | Too Many Requests | 指示用户在给定时间内发送了太多请求(“限速”),配合 Retry-After(多长时间后可以请求)响应头一起使用 |
431 | Request Header Fields Too Large | 请求头太大,服务器不愿意处理请求,因为它的头部字段太大。请求可以在减少请求头域的大小后重新提交。 |
500 | Internal Server Error | 服务器发生不可预期的错误。服务器出异常了,赶紧看日志去吧 |
503 | Service Unavailable | 服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好 |
状态码大全:https://cloud.tencent.com/developer/chapter/13553
- 目前阶段只需要知道:
- 200、404、500
四、HTTP协议-协议解析
1. 客户端
- 客户端浏览器各大厂商给我们提供了,里面已经内置了
解析HTTP协议的程序
- 因此当服务端给客户端浏览器响应对应的数据后,客户端浏览器会自动解析
2. 服务端
- 在服务器端通过Java程序接收客户端浏览器发起的请求并获取请求数据
- 然后参照前面介绍的HTTP协议请求数据格式对请求数据进行解析
- 最后参照前面介绍的HTTP协议响应数据格式给客户端浏览器响应对应的数据
- 服务端程序实现HTTP协议解析程序:
(1)我们可以Socket、ServerSocket可以写出一个服务器端的程序
(2)然后浏览器发送HTTP请求,我们通过ServerSocket来接收客户端发起的请求并获取到请求数据
(3)这些请求数据就是一些字符串,格式就是之前介绍过的,根据字符串的组成规则解析它
(4)通过ServerSocket来获取到输出流,按照HTTP响应数据格式给浏览器响应一个固定格式的字符串
-
Server.java
package com.itheima; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; /* * 自定义web服务器 */ public class Server { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(8081); // 监听指定端口 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(); 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文件,转换为字符串 InputStream is = Server.class.getClassLoader().getResourceAsStream("html/a.html"); BufferedReader br = new BufferedReader(new InputStreamReader(is)); 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(); } } }
-
a.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1" cellspacing="0" width="500"> <tr> <th>序号</th> <th>品牌名称</th> <th>企业名称</th> </tr> <tr align="center"> <td>010</td> <td>三只松鼠</td> <td>三只松鼠</td> </tr> <tr align="center"> <td>009</td> <td>优衣库</td> <td>优衣库</td> </tr> <tr align="center"> <td>008</td> <td>小米</td> <td>小米科技有限公司</td> </tr> </table> </body> </html>
3. 软件解析
-
如果我们真的要写一个程序来解析HTTP协议,是要考虑到各种情况的,里面东西很多。
-
代码量也是相当大,繁琐。
-
但是所有web开发都是要解析HTTP协议的,因此是通用的。
-
所以有很多公司已经把这些代码写好了,并封装到一个软件程序中提供给我们使用,这个软件就是
Web服务器
-
Web服务器有很多:
-
有了这些Web服务器,HTTP解析和处理的代码都不用我们去做了!!这样更加便捷、高效。