前言
很多同学在学习到Servlet的时候,需要通过Tomcat去接收HTTP的响应以实现这个前后端交互的场景,因此理解起来就比较困难,之前在写Java代码的时候,我们只是在一个程序里面通过方法1调用方法2以达成基本的代码逻辑。不过现在呢,我们是去进行一个前后端的交互,本质实现的是两个程序之间的相互通信
- 这就需要去理解一个接口的思想,后端Servlet通过注解的形式去为前端提供一个访问的接口,前端只需要通过这个找到对应的服务器接口,Tomcat服务器就会将HTTP请求解析为
request
对象,以此很好地在内部通过Servlet来处理这个对象,再构造出response
对象由返回给Tomcat,最后由Tomcat继续解析为HTTP响应返回给浏览器
还是有点不同的同学可以看看下面这个动图,解释得很好,出自JavaWeb——Servlet
如何构造HTTP请求?
当然,前端在给后端发送HTTP请求之前,它要先构造出这个请求才行,下面我介绍三种构造HTTP请求的方式
1、通过form表单构造HTTP请求
① form发送GET请求
- 那首先我们要去写一个表单
- 【action】属性为
https://www.sogou.com/
,也就是指定表单要提交到的地址处(URL),这里是交给搜狗的服务器来处理我们所提交的表单内容 - 【method】属性为
get
,表示在提交表单时所需要用到的HTTP方法,这里的话是使用get(默认),不过对于表单来说我们用的都是post,下一小节会介绍
- 写好form表单的属性后,里面就是供用户操作的一些控件,分别为两个输入框和一个提交按钮,可以看到两个输入文本框我不仅设置了必要的【type】属性,而且还分别设置了【name】属性,为的就是实现的header(请求头)中所呈现==键值对==
<form action="https://www.sogou.com/" method="get"> <input type="text" name="UserId"> <input type="text" name="ClassId"> <!-- 点击这个按钮会触发form表单的提交操作,也就是构造HTTP请求发给服务器 --> <input type="submit" value="提交"> </form>
- 可以看到,当我点击提交的时候,就来到了搜狗的主页
- 接着我们通过Fiddler抓包工具就可以去查看这个HTTP请求,对于GET请求来说,我们主要看这个第一行就可以了
==下面是我们对form表单的设置与HTTP请求报文发生的对应变化==
② form发送POST请求
- 当然,form表单除了向服务器发送GET请求外,还可以发送POST请求,只需要修改一下这个【method】属性即可
<form action="https://www.sogou.com/" method="post"> <input type="text" name="UserId"> <input type="text" name="ClassId"> <!-- 点击这个按钮会触发form表单的提交操作,也就是构造HTTP请求发给服务器 --> <input type="submit" value="提交"> </form>
- 然后我们看到form表单所发送过来的HTTP请求的原生文件,可以观察到与GET请求相比,里面的内容出现了差距
- 然后我们来分析一下这个报文格式的变化,可以看到对于form构造的post请求来说,body里面的数据格式就和query string是非常相似的,也是【键值对结构
- 键值对之间用
&
来分割 - 键和值之间用
=
来分割
2、通过Ajax构造HTTP请求
当然,除了form表单之外,我们还有一种功能更强的构造HTTP请求的方式,那就是通过ajax来实现
同步等待与异步等待的感性理解
【概念】:ajax 全称 Asynchronous Javascript And XML
, 是 2005 年提出的一种 JavaScript 给服务器发送HTTP 请求的方式.
- 其最大的特点就是:可以不需要刷新页面/页面跳转 就能进行数据传输.
- 其实ajax最需要关注的点就是
Asynchronous
,也就是【异步】的意思,【同步】相信学习过多线程的同学都有听说过,使用关键字synchronized
就可以去实现了,那我们就要来谈谈这个【同步】和【异步】的区别了
我在这里举一个形象点的例子
- 比如说你现在和你和女朋友在谈恋爱,你呢想约她出去玩,于是来到她的宿舍楼下,打电话问她什么时候出来,此时她说:“等一下”,但是呢一般女生说的等一下通常不是三五分钟,起码是半个小时起步⏰于是呢你就开始了漫长的等待~~
- 如果你只是戴戴地望着宿舍大门等她出来,等到她露头就马上迎上去,此时就叫做【同步的等待】
- 如果你觉得这么等着比较无聊,然后来到了宿舍楼下周围的树荫下打开了你心爱的《Java编程思想》,那么此时你也是在等待,不过这叫做【异步的等待】
相信通过上述这个案例你一定理解了什么是【同步等待】和【异步等待】了
==A 等待 B==
👉 A始终盯着B,A负责关注B啥时候就绪👉 A不盯着B,B就绪之后主动通知A
- HTML中,通过ajax 发起http请求,就属于是 “异步” 方式,现在我们就来说说如何使用ajax去发起http请求
- 不过呢在实现ajax前我们要先引入一个外部的jQuery,它是一种流行的 JavaScript 库,通过封装常见任务和跨浏览器兼容性问题来使 JavaScript 更易于使用
- 首先进入bootcdn的官网,把这段链接复制下来即可,然后将其粘贴到
<script>
的src属性中,表示引入一个外部的js文件
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
- 接下去我们就可以去构造ajax请求了,需要构造的内容其实和form表单类似,只是属性有所不同罢了
- 在form表单中我们所写的
method
,这里变成了type
; - 在form表单中我们所写的
action
,这里变成了url
;
- 其实它们本质还是相同的,只是换了个说法而已。然后接下去呢就可以看到有一个
success
属性,它的内部似乎是一个function函数。这里要重点说一下,它就是我们在C语言中所学习的回调函数,这个底层的逻辑是类似的,当我们通过ajax构造的HTTP请求到达服务器后,服务器再进行处理将其返回给浏览器,此时浏览器就会触发该回调函数,去进行执行相应的代码 - 上述的这个回调逻辑其实就体现了【异步】的思想,ajax不需要等待浏览器给它响应,就可以先把自己的代码先跑完,所以我们可以预期一下console控制台中的第一句便是这个【浏览器立即往下执行后续代码】
<script> $.ajax({ type: 'get', url: "https://www.sogou.com/", // 此处的success就声明了一个回调函数,就会在服务器响应,回到浏览器的时候触发该回调 // 正是此处的回调体现了 “异步” success: function(data){ console.log("当服务器返回的响应到达浏览器后,浏览器触发该回调,通知到咱们的代码中"); } }) console.log("浏览器立即往下执行后续代码"); </script>
- 通过去console控制台进行观察我们可以发现打印出来的结果是【浏览器立即往下执行后续代码】,这就意味着它是在回调函数之前执行的,但回调函数没有执行只是因为搜狗那里的服务器并没有处理我们呢发送过去的HTTP请求,所以便报出了异常,后面我们自己通过Tomcat去模拟服务器调用Servlet来进行处理即可
【小结一下】:
- 和form相比,ajax功能更强
- 支持put、delete等方法
- ajax发送的请求可以灵活设置header
- ajax发送的请求body也可以灵活设置
3、使用postman构造HTTP请求
对于postman而言,它是专门用来进行http请求测试的工具,如有不懂可以看看这篇文章链接
- 有关如何去构造HTTP请求,我下面做一个演示,很简单,只需要点点鼠标即可🖱
- 此时搜狗那边就可以收到我们的HTTP请求了,但是人家不给出回应也没办法查看,下面我们自己去实现前后端交互的时候我会继续做演示
4、通过 Java socket 构造 HTTP 请求
上面三种是我们在平常工作中用得最多的,还有一种就是通过 Java socket 来进行构造,可以了解一下~
public class HttpClient { private Socket socket; private String ip; private int port; public HttpClient(String ip, int port) throws IOException { this.ip = ip; this.port = port; socket = new Socket(ip, port); } public String get(String url) throws IOException { StringBuilder request = new StringBuilder(); // 构造首行 request.append("GET " + url + " HTTP/1.1\n"); // 构造 header request.append("Host: " + ip + ":" + port + "\n"); // 构造 空行 request.append("\n"); // 发送数据 OutputStream outputStream = socket.getOutputStream(); outputStream.write(request.toString().getBytes()); // 读取响应数据 InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024 * 1024]; int n = inputStream.read(buffer); return new String(buffer, 0, n, "utf-8"); } public String post(String url, String body) throws IOException { StringBuilder request = new StringBuilder(); // 构造首行 request.append("POST " + url + " HTTP/1.1\n"); // 构造 header request.append("Host: " + ip + ":" + port + "\n"); request.append("Content-Length: " + body.getBytes().length + "\n"); request.append("Content-Type: text/plain\n"); // 构造 空行 request.append("\n"); // 构造 body request.append(body); // 发送数据 OutputStream outputStream = socket.getOutputStream(); outputStream.write(request.toString().getBytes()); // 读取响应数据 InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024 * 1024]; int n = inputStream.read(buffer); return new String(buffer, 0, n, "utf-8"); } public static void main(String[] args) throws IOException { HttpClient httpClient = new HttpClient("42.192.83.143", 8080); String getResp = httpClient.get("/AjaxMockServer/info"); System.out.println(getResp); String postResp = httpClient.post("/AjaxMockServer/info", "this is body"); System.out.println(postResp); } }