
前端基础知识
前端基础
1.什么是 HTTP 请求?
HTTP(HyperText Transfer Protocol,超文本传输协议)是浏览器和服务器之间通信的协议。
当你在浏览器输入一个网址、或者前端调用接口时,实际上就是在向服务器发出 HTTP 请求。
一个 HTTP 请求一般包含三部分:
请求行(Request Line)
包括请求方法(GET/POST等)、请求 URL、HTTP 版本。
例子:
GET /index.html HTTP/1.1
请求头(Request Headers)
携带附加信息,比如客户端信息、请求格式、认证信息、缓存控制等。
例子:
Host: www.example.com User-Agent: Mozilla/5.0 Content-Type: application/json
现在一般都用
Content-Type: application/json
这个格式了,另外的格式有兴趣自行Google。
请求体(Request Body)
主要在 POST/PUT 请求中,用于传输数据,比如表单信息、JSON 数据。
例子:
{ "username": "jack", "password": "123456" }
2. 常见的 HTTP 请求方法
(1)GET 请求
作用:从服务器获取数据(读取资源)。
特点:
参数一般拼接在 URL 上(如
?id=1&name=jack
)。没有请求体(理论上可有,但规范上不推荐)。
幂等:多次请求结果相同。
例子:
GET /user?id=1 HTTP/1.1 Host: example.com
(2)POST 请求
作用:向服务器提交数据(创建/修改资源)。
特点:
数据一般放在请求体里。
比 GET 更适合传输大数据(比如 JSON、文件上传)。
不是幂等的,每次请求可能有不同结果。
例子:
POST /login HTTP/1.1 Host: example.com Content-Type: application/json { "username": "jack", "password": "123456" }
(3)其他常见方法
PUT:更新资源(整体更新)。
PATCH:更新资源(部分更新)。
DELETE:删除资源。
HEAD:只获取响应头,不返回具体数据。
OPTIONS:获取服务器支持的方法,常用于跨域请求的预检。
3. 请求头(Request Headers)
请求头用来告诉服务器客户端的一些信息或者请求的规则。常见的有:
Host:目标服务器的域名/IP。
User-Agent:客户端信息(浏览器、操作系统等)。
Accept:告诉服务器客户端希望接受的数据类型(如
application/json
)。Content-Type:请求体的数据类型,比如:
application/json
→ JSON 格式数据application/x-www-form-urlencoded
→ 表单数据multipart/form-data
→ 文件上传
Authorization:认证信息(比如 Token、JWT)。
Cookie:客户端携带的会话信息。
4. 请求体(Request Body)
GET 请求一般没有请求体,参数写在 URL 上。
POST/PUT/PATCH 通常在请求体中提交数据,常见格式:
表单:
application/x-www-form-urlencoded
username=jack&password=123
JSON:
application/json
{ "username": "jack", "password": "123" }
文件上传:
multipart/form-data
5. 请求和响应的关系
请求(Request):客户端发起的消息。
响应(Response):服务器返回的结果。
响应也有三部分:响应行(状态码,如
200 OK
、404 Not Found
)响应头(如 Content-Type, Set-Cookie)
响应体(实际的数据,比如 HTML、JSON、图片等)
6.Session原理
HTTP是无状态,有会话的:
无状态是指,请求之间相互独立,第一次请求的数据,第二次请求不能复用。
有会话是指,客户端和服务端都有相应的技术,可以暂存数据,让数据在请求之间共享。
服务端使用Session技术来暂存数据,当请求送到服务端,服务端创建一个Session对象,来存数据,Session对象可以简单理解为一个Key-Value的键值对数据结构。当别的请求送到服务端的时候,服务端会创建一个新的Session对象,来存储该请求的数据。当一个请求过来之后,它用啥来找到它起初创建的Session对象呢?当Session对象创建的时候,回给请求方返回一个jsessionid,不同的Session被创建的时候,产生的jsessionid都不一样。当下次请求来的时候,会带上这个jsessionid,那么服务端就可以知道这个请求在请求哪个Session。
下面我们来模拟这个过程:
后端代码:
@Controller
@RequestMapping("/test")
public class MyController {
@RequestMapping("/s1")
@ResponseBody
public String s1(HttpSession session, String name) {
session.setAttribute("name", name);
return "数据已存储!";
}
@RequestMapping("/s2")
@ResponseBody
public String s2(HttpSession session) {
return "取出数据" + session.getAttribute("name");
}
}
使用Telnet发送请求:
存
GET /test/s1?name=zhang HTTP/1.1
Host: localhost
服务端响应:
注意看我们得到了一个Sessionid,把它记下,后面要用!
取:
GET /test/s2 HTTP/1.1
Host: localhost
Cookie: JSESSIONID=AD6B5E162B5B52E47DF609681A0D51AD
服务器响应:
Session技术实现身份验证:
但是这个验证只适用于单体项目,分布式项目可以使用jwt技术
jwt技术实现身份验证
下面我们使用Telnet来模拟这一过程,这里我使用hutool工具类,构造token:
package com.hanserwei.frontprelearn.controller;
import cn.hutool.jwt.JWTUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/test")
public class MyController {
// 密钥,实际项目中应该放在配置文件中
private static final String SECRET_KEY = "mySecretKey123456";
/**
* JWT登录验证示例
*/
@RequestMapping("/login")
@ResponseBody
public String j1(String name, String pass) {
if (name.equals("hanserwei") && pass.equals("123456")) {
// 创建payload内容
Map<String, Object> payload = new HashMap<>();
payload.put("username", name);
payload.put("loginTime", System.currentTimeMillis());
// 使用Hutool生成JWT token
String token = JWTUtil.createToken(payload, SECRET_KEY.getBytes());
return "登录成功!token: " + token;
} else {
return "登录失败!用户名或密码错误";
}
}
/**
* 验证JWT token示例
*/
@RequestMapping("/verify")
@ResponseBody
public String verifyToken(@RequestHeader("Authorization") String authorization) {
try {
// 验证token是否有效
boolean verify = JWTUtil.verify(authorization, SECRET_KEY.getBytes());
if (verify) {
// 解析token中的信息
Map<String, Object> payload = JWTUtil.parseToken(authorization).getPayloads();
return "Token验证成功!用户信息: " + payload.get("username");
} else {
return "Token验证失败!";
}
} catch (Exception e) {
return "Token解析异常: " + e.getMessage();
}
}
}
取token:
GET /test/login?name=hanserwei&pass=123456 HTTP/1.1
Host: localhost
验证token:
我们使用刚刚的token,来验证一下:
GET /test/verify HTTP/1.1
Host: localhost
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblRpbWUiOjE3NTU5NTYzNDIyMDQsInVzZXJuYW1lIjoiaGFuc2Vyd2VpIn0.7wrv4X4qmsRLJHCJRy2F2cAgSDb4gqKlpNu818KOVwU
这里顺便说一下这个token咋来的,其实一个token可以看做三部分,以.
分割,第一部分是算法签名部分(header),第二部分数据(payload),第三部分是签名。其中前两部分都没有加密,都是JSON字符串,只不过用了Base64编码而已,我可以直接Decode看一下:
import org.junit.jupiter.api.Test;
import java.util.Base64;
public class JwtTest {
@Test
public void test() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblRpbWUiOjE3NTU5NTYzNDIyMDQsInVzZXJuYW1lIjoiaGFuc2Vyd2VpIn0.7wrv4X4qmsRLJHCJRy2F2cAgSDb4gqKlpNu818KOVwU";
System.out.println(new String(Base64.getDecoder().decode(token.split("\\.")[0])));
System.out.println(new String(Base64.getDecoder().decode(token.split("\\.")[1])));
}
}
输出:
{"typ":"JWT","alg":"HS256"}
{"loginTime":1755956342204,"username":"hanserwei"}
可以看到,签名算法用到了”HS25“算法,这个不用去深究,就是一个签名算法而已!第二部分包含了在login的时候存的数据。token的安全性在于第三步份,可以保证token的属性不会被篡改!
比如我现在的hanserwei
是个普通用户,而管理员是bigdty
,那么我们可以把用户改成bigdty
然后发给服务端吗?
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class JwtTest {
@Test
public void test() {
String str = """
{"loginTime":1755956342204,"username":"bigdty"}
""";
System.out.println(Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8)));
}
}
先把{"loginTime":1755956342204,"username":"bigdty"}
进行Base64编码。
eyJsb2dpblRpbWUiOjE3NTU5NTYzNDIyMDQsInVzZXJuYW1lIjoiYmlnZHR5In0K
然后替换我们token的第二部分,然后发送给服务端:
GET /test/verify HTTP/1.1
Host: localhost
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblRpbWUiOjE3NTU5NTYzNDIyMDQsInVzZXJuYW1lIjoiYmlnZHR5In0K.7wrv4X4qmsRLJHCJRy2F2cAgSDb4gqKlpNu818KOVwU
结果当然是验证失败啦:
这其实是和第三部分有关,第三部分是由前两部分,加一个密钥,然后通过一个签名算法得出,而密钥只有服务端知道。只要我们改了前面两部分的任何一个部分,那么通过签名算法算出来结果就不一样。所以就G了。过不了验证!