目录
一:HTTP协议概述
二:HTTP协议实操
三:模板方法设计模式
什么是协议?
协议实际上是某些人,或者某些组织提前制定好的一套规范、一套标准。
什么是HTTP协议?
HTTP协议:是W3C制定的一种超文本传输协议。(通信协议:发送消息的模板提前被制定好)
W3C:万维网联盟组织
负责制定标准的,例如:HTTP HTML4.0 HTML5 XML DOM等规范都是W3C制定的。
万维网之父:蒂姆·伯纳斯·李
什么是超文本?
超文本说的就是不是普通文本,比如流媒体:声音、视频、图片等。
HTTP协议支持:不但可以传送普通字符串,同样支持传递声音、视频、图片等流媒体信息。
这种协议游走在B和S之间;B向S发数据要遵循HTTP协议,S向B发数据同样需要遵循HTTP协议;这样B和S才能解耦合。
什么是解耦合?
B不依赖S,S也不依赖B。
B/S表示:B/S结构的系统(浏览器访问WEB服务器的系统)
浏览器 向 WEB服务器发送数据,叫做:请求(request)
WEB服务器 向 浏览器发送数据,叫做:响应(response)
HTTP协议包括:
请求协议
浏览器 向 WEB服务器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
响应协议
WEB服务器 向 浏览器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
HTTP协议就是提前制定好的一种消息模板。浏览器不依赖具体的服务器品牌,WEB服务器也不依赖具体的浏览器品牌。
定义两个类实现GenericServlet
package com.bjpowernode.javaweb.servlet;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class GetServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
// 设置响应的类型
response.setContentType("text/html");
// 打印到浏览器上
PrintWriter out = response.getWriter();
// out.println() 是输出信息到浏览器,最终源代码中换行。
// (不是网页上有换行效果,网页上有换行效果必须使用
)
out.println("");
out.println("");
out.println(" ");
out.println(" from get servlet ");
out.println(" ");
out.println(" ");
out.println(" from post servlet
");
out.println(" ");
out.println("");
}
}
package com.bjpowernode.javaweb.servlet;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class PostServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
// 设置响应的类型
response.setContentType("text/html");
// 打印到浏览器上
PrintWriter out = response.getWriter();
// out.println() 是输出信息到浏览器,最终源代码中换行。
// (不是网页上有换行效果,网页上有换行效果必须使用
)
out.println("");
out.println("");
out.println(" ");
out.println(" from post servlet ");
out.println(" ");
out.println(" ");
out.println(" from post servlet
");
out.println(" ");
out.println("");
}
}
编写web.xml配置文件
get
com.bjpowernode.javaweb.servlet.GetServlet
get
/getServlet
post
com.bjpowernode.javaweb.servlet.PostServlet
post
/postServlet
编写一个index.html文件,里面定义两个表单:一个get请求的表单、一个post请求的表单
http协议
get请求
post请求
1、HTTP的请求协议(B --> S)
HTTP的请求协议包括:4部分
请求
请求头
空白行
请求体
HTTP请求协议的具体报文:GET请求
GET /servlet05/getServlet?username=jack&userpwd=123 HTTP/1.1 请求行
Host: localhost:8080 请求头
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
空白行
请求体
HTTP请求协议的具体报文:POST请求
POST /servlet05/postServlet HTTP/1.1 请求行
Host: localhost:8080 请求头
Connection: keep-alive
Content-Length: 29
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
空白行
username=zhangsan&userpwd=123 请求体
请求行包括三部分:
第一部分:请求方式(7种)
trace
options
head
put
delete
post(常用)
get(常用)
第二部分:URI
什么是URI? 统一资源标识符。代表网络中某个资源的名字。但是通过URI是无法定位资源的。
什么是URL?统一资源定位符。代表网络中某个资源,同时,通过URL是可以定位到该资源的。
URI和URL什么关系,有什么区别?
URL是包括URI的
http://localhost:8080/servlet05/index.html 这是URL。
/servlet05/index.html 这是URI。
第三部分:HTTP协议版本号
请求头
请求的主机
主机的端口
浏览器信息
平台信息
cookie等信息
....
空白行
空白行是用来区分“请求头”和“请求体”
请求体
向服务器发送的具体数据。
2、HTTP的响应协议(S --> B)
HTTP的响应协议包括:4部分
状态行
响应头
空白行
响应体
HTTP响应协议的具体报文:
HTTP/1.1 200 ok 状态行
Content-Type: text/html;charset=UTF-8 响应头
Content-Length: 32
Date: Sat, 05 Nov 2022 08:12:19 GMT
Keep-Alive: timeout=20
Connection: keep-alive
空白行
响应体
from post servlet
from get servlet
状态行由三部分组成:
第一部分:协议版本号(HTTP/1.1)
第二部分:状态码(HTTP协议中规定的响应状态号,不同的响应结果对应不同的号码)。
200 表示请求响应成功,正常结束。
404表示访问的资源不存在,通常是因为路径写错了,或者是路径写对了,但是服务器中对应的资源并没有启动成功。总之404错误是前端错误!
405表示前端发送的请求方式与后端请求的处理方式不一致时发生,例如:
前端是POST请求,后端的处理方式按照get方式进行处理时,发生405
500表示服务器端的程序出现了异常。一般会认为是服务器端的错误导致的。
以4开始的,一般是浏览器端的错误导致的。
以5开始的,一般是服务器端的错误导致的。
第三部分:状态的描述信息
ok 表示正常成功结束。
not found 表示资源找不到。
响应头(了解):
响应的内容类型
响应的内容长度
响应的时间
....
空白行:
用来分隔“响应头”和“响应体”的。
响应体:
响应体就是响应的正文,这些内容是一个长的字符串,这个字符串被浏览器渲染,解释并执行,最终展示出效果。
3、怎么查看的协议内容?
使用chrome浏览器:F12。然后找到network,通过这个面板可以查看协议的具体内容。
4、怎么向服务器发送GET请求,怎么向服务器发送POST请求?
到目前为止,只有一种情况可以发送POST请求:使用form表单,并且form标签中的method属性值为:method="post"。
其他所有情况一律都是get请求:
在浏览器地址栏上直接输入URL,敲回车,属于get请求。
在浏览器上直接点击超链接,属于get请求。
使用form表单提交数据时,form标签中没有写method属性,默认就是get
或者使用form的时候,form标签中method属性值为:method="get"
5、 GET请求和POST请求有什么区别?
get请求发送数据的时候,数据会挂在URI的后面,并且在URI后面添加一个“?”,"?"后面是数据。这样会导致发送的数据回显在浏览器的地址栏上。(get请求在“请求行”上发送数据)
http://localhost:8080/servlet05/getServlet?username=zhangsan&userpwd=1111
post请求发送数据的时候,在请求体当中发送。不会回显到浏览器的地址栏上,也就是说post发送的数据,在浏览器地址栏上看不到。(post在“请求体”当中发送数据)
get请求只能发送普通的字符串。并且发送的字符串长度有限制,不同的浏览器限制不同。
post请求可以发送任何类型的数据,包括普通字符串,流媒体等信息:视频、声音、图片,理论上没有长度限制。
get请求无法发送大数据量,post请求可以发送大数据量。
get请求比较适合从服务器端获取数据,post请求比较适合向服务器端传送数据。
get请求是安全的。get请求是绝对安全的。为什么?因为get请求只是为了从服务器上获取数据,不会对服务器造成威胁。
post请求是危险的。为什么?因为post请求是向服务器提交数据,如果这些数据通过后门的方式进入到服务器当中,服务器是很危险的。另外post是为了提交数据,所以一般情况下拦截请求的时候,大部分会选择拦截(监听)post请求。
get请求支持缓存。
任何一个get请求最终的“响应结果”都会被浏览器缓存起来。
在浏览器缓存当中:一个get请求的路径 对应 一个资源。
实际上,你只要发送get请求,浏览器做的第一件事都是先从本地浏览器缓存中找,找不到的时候才会去服务器上获取。这种缓存机制目的是为了提高用户的体验。
有没有这样一个需求:我们不希望get请求走缓存,怎么办?怎么避免走缓存?我希望每一次这个get请求都去服务器上找资源,我不想从本地浏览器的缓存中取。
只要每一次get请求的请求路径不同即可。
怎么解决?可以在路径的后面添加一个每时每刻都在变化的“时间戳”,这样,每一次的请求路径都不一样,浏览器就不走缓存了。
post请求不支持缓存。(POST是用来修改服务器端的资源的。)
post请求之后,服务器“响应的结果”不会被浏览器缓存起来。因为这个缓存没有意义。
6、GET请求和POST请求如何选择,什么时候使用GET请求,什么时候使用POST请求?
怎么选择GET请求和POST请求呢?衡量标准是什么呢?
看这个请求是想获取服务器端的数据,还是想向服务器发送数据。
如果你是想从服务器上获取资源,建议使用GET请求,
如果你这个请求是为了向服务器提交数据,建议使用POST请求。
大部分的form表单提交,都是post方式,因为form表单中要填写大量的数据,这些数据是收集用户的信息,一般是需要传给服务器,服务器将这些数据保存/修改等。
如果表单中有敏感信息,还是建议适用post请求,因为get请求会回显敏感信息到浏览器地址栏上。(例如:密码信息)
做文件上传,一定是post请求,要传的数据不是普通文本。
其他情况都可以使用get请求。
7、不管是get请求还是post请求,发送的请求数据格式是完全相同的,只不过位置不同,格式都是统一的
格式:name=value&name=value&name=value&name=value
name是什么?
以form表单为例:form表单中输入域input标签的name属性。
value是什么?
以form表单为例:form表单中输入域input标签的value属性。
什么是设计模式?
某个问题的固定的解决方案。(可以被重复使用。)
有哪些设计模式?
GoF设计模式:通常我们所说的23种设计模式。(Gang of Four:4人组提出的设计模式)
单例模式
工厂模式
代理模式
门面模式
责任链设计模式
观察者模式
模板方法设计模式
.....
JavaEE设计模式:
DAO
DTO
VO
PO
pojo
....
....
什么是模板方法设计模式?
在模板类的模板方法当中定义核心算法骨架,具体的实现步骤可以延迟到子类当中完成。
模板类通常是一个抽象类,模板类当中的模板方法定义核心算法,这个方法通常是final的(但也可以不是final的)
模板类当中的抽象方法就是不确定实现的方法,这个不确定怎么实现的事交给子类去做。
例1:定义两个Student类和Teacher类,其它方法都相同,只有doSome()方法不同
存在的问题:
第一:算法没有得到重复的使用。
第二:代码没有得到复用。
Student类
package com.bjpowernode.template1;
public class Student {
//这个方法描述学生的一天
public void day(){
// 和Teacher的算法相同。
qiChuang();
xiShu();
chiZaoCan();
doSome();
chiWanFan();
shuiJiao();
}
public void qiChuang(){
System.out.println("起床");
}
public void xiShu(){
System.out.println("洗漱");
}
public void chiZaoCan(){
System.out.println("吃早餐");
}
// 只有doSome()方法不同
public void doSome(){
System.out.println("学生上学,学习");
}
public void chiWanFan(){
System.out.println("吃晚饭");
}
public void shuiJiao(){
System.out.println("睡觉");
}
}
Teacher类
package com.bjpowernode.template1;
public class Teacher {
// 这个方法描述老师的一天
public void day(){
// 和Student的算法相同。
qiChuang();
xiShu();
chiZaoCan();
doSome();
chiWanFan();
shuiJiao();
}
public void qiChuang(){
System.out.println("起床");
}
public void xiShu(){
System.out.println("洗漱");
}
public void chiZaoCan(){
System.out.println("吃早餐");
}
// 只有这个方法不同
public void doSome(){
System.out.println("老师正在课堂上授课,教授学生知识");
}
public void chiWanFan(){
System.out.println("吃晚饭");
}
public void shuiJiao(){
System.out.println("睡觉");
}
}
例2:使用模板方法设计模式进行优化
Teacher和Student都是Person
第一:Person就是模板方法设计模式当中的模板类。
第二: day()方法就是模板方法设计模式当中的模板方法。
模板类Person类
package com.bjpowernode.template2;
public abstract class Person { // 模板类通常是抽象类。
// 模板方法
// 添加了final之后,这个方法无法被覆盖,这样核心的算法也可以得到保护。
// 模板方法定义核心的算法骨架,具体的实现步骤可以延迟到子类当中去实现。
// 核心算法一方面是得到了保护,不能被改变。另外一方面就是算法得到了重复使用。
// 另外代码也得到了复用,因为算法中某些步骤的代码是固定的。这些固定的代码不会随着子类的变化而变换,这一部分代码可以写到模板类当中。
public final void day(){
// 第一步
qiChuang();
// 第二步
xiShu();
// 第三步
chiZaoCan();
// 第四步
doSome();
// 第五步
chiWanFan();
// 第六步
shuiJiao();
}
// 其中的某些步骤,不会随着子类的变化而变化,这些代码可以写到父类中,得到代码复用。
public void qiChuang(){
System.out.println("起床");
}
public void xiShu(){
System.out.println("洗漱");
}
public void chiZaoCan(){
System.out.println("吃早餐");
}
// 写成抽象方法:这一步是要做,但是具体这一步怎么做,子类说了算。
public abstract void doSome();
public void chiWanFan(){
System.out.println("吃晚饭");
}
public void shuiJiao(){
System.out.println("睡觉");
}
}
Student类继承Person类
package com.bjpowernode.template2;
public class Student extends Person {
public void doSome(){
System.out.println("学生上学,学习");
}
}
Teacher类继承Person类
package com.bjpowernode.template2;
public class Teacher extends Person{
public void doSome(){
System.out.println("老师正在课堂上授课,教授学生知识");
}
}
Test类进行测试调用
package com.bjpowernode.template2;
public class Test {
public static void main(String[] args) {
// 实用多态
Person p1 = new Teacher();
p1.day();
System.out.println("-----------------");
Person p2 = new Student();
p2.day();
}
}