Java Web 7-10
- [7. 开发第一个 Servlet](#7. 开发第一个 Servlet)
-
- [7.1 创建项目的标准目录](#7.1 创建项目的标准目录)
- [7.2 编写 Servlet](#7.2 编写 Servlet)
- [7.3 编译 Servlet](#7.3 编译 Servlet)
- [编译后拷贝到 classes 目录](#编译后拷贝到 classes 目录)
- [7.4 编写 web.xml 配置](#7.4 编写 web.xml 配置)
- [7.5 部署项目到 Tomcat](#7.5 部署项目到 Tomcat)
- [启动 Tomcat 打开浏览器访问](#启动 Tomcat 打开浏览器访问)
- [7.6 使用超链接发送请求](#7.6 使用超链接发送请求)
- [7.7 响应一段中文到浏览器](#7.7 响应一段中文到浏览器)
- [8. Servlet 连接数据库](#8. Servlet 连接数据库)
-
- [8.1 添加 mysql 驱动](#8.1 添加 mysql 驱动)
- [8.2 编写 DeptListServlet](#8.2 编写 DeptListServlet)
- [8.3 编写 web.xml](#8.3 编写 web.xml)
- [8.4 提供超链接](#8.4 提供超链接)
- [8.5 部署测试](#8.5 部署测试)
- [9. IDEA 开发 Servlet](#9. IDEA 开发 Servlet)
-
- [9.1 创建空项目](#9.1 创建空项目)
- [9.2 创建普通 java 模块](#9.2 创建普通 java 模块)
- [9.3 创建 web 目录作为 webapproot](#9.3 创建 web 目录作为 webapproot)
- [9.4 添加 web 支持](#9.4 添加 web 支持)
- [9.5 添加 Artifact(构件)](#9.5 添加 Artifact(构件))
- [将 servlet-api.jar 添加到 classpath 中](#将 servlet-api.jar 添加到 classpath 中)
- [9.6 添加数据库驱动](#9.6 添加数据库驱动)
- [9.7 编写 Servlet 和 web.xml](#9.7 编写 Servlet 和 web.xml)
- [9.8 IDEA 配置 Tomcat](#9.8 IDEA 配置 Tomcat)
- [9.9 部署构件到 Tomcat](#9.9 部署构件到 Tomcat)
- [9.10 启动 Tomcat 测试](#9.10 启动 Tomcat 测试)
- [10. HTTP协议](#10. HTTP协议)
-
- [10.1 什么是HTTP协议](#10.1 什么是HTTP协议)
- [10.2 HTTP请求报文详解](#10.2 HTTP请求报文详解)
- [10.3 HTTP响应报文详解](#10.3 HTTP响应报文详解)
- [10.4 GET与POST的区别及选择](#10.4 GET与POST的区别及选择)
-
- [10.4.1 区别](#10.4.1 区别)
- [10.4.2 如何选择](#10.4.2 如何选择)
- [10.4.3 怎么发送 POST 请求](#10.4.3 怎么发送 POST 请求)
- [10.5 URL编码](#10.5 URL编码)
-
- [10.5.1 URL编码的作用](#10.5.1 URL编码的作用)
- [10.5.2 前端系统中什么情况下需要手动编码](#10.5.2 前端系统中什么情况下需要手动编码)
- [10.5.3 后端系统中什么情况下需要手动编码](#10.5.3 后端系统中什么情况下需要手动编码)
7. 开发第一个 Servlet
7.1 创建项目的标准目录
在任意位置创建一个目录 web01,作为项目的根目录。然后在该目录下按照以下目录结构创建:
plain
web01
|-------WEB-INF
|-------classes

7.2 编写 Servlet
在任意位置创建 HelloServlet.java。

任何 Servlet都必须实现 jakarta.servlet.Servlet接口,该接口中有哪些方法呢?参考帮助文档:

编写 HelloServlet实现该接口中所有方法:
java
package com.jkweilai.servlet;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.ServletConfig;
import java.io.PrintWriter;
import java.io.IOException;
// HelloServlet对象的创建以及这个对象上方法的调用,都是Tomcat服务器负责的。
// 程序员只提供实现类和实现方法。程序员不能自己new HelloServlet(),也不能自己手动调用方法。
public class HelloServlet implements Servlet{
public void init(ServletConfig config) throws ServletException{}
// 这个回调函数是Servlet的核心方法。
// 每一次请求,这个方法都会被调用。
public void service(ServletRequest request,ServletResponse response)
throws ServletException, IOException{
// 向控制台打印
System.out.println("Hello Servlet!");
// 向浏览器上响应HTML
PrintWriter out = response.getWriter();
out.print("<h1>Hello Servlet!</h1>");
}
public void destroy(){}
public String getServletInfo(){
return "";
}
public ServletConfig getServletConfig(){
return null;
}
}
7.3 编译 Servlet
配置环境变量 CLASSPATH:

思考,为什么要配置 CLASSPATH 环境变量,另外环境变量中为什么要添加一个 .
编译:

以上编译命令表示:编译当前目录下的 HelloServlet.java文件,将编译之后的程序放到当前目录下。
编译之后生成了:

编译后拷贝到 classes 目录
将以上编译之后的结果拷贝到 WEB-INF/classes目录下:

7.4 编写 web.xml 配置
Tomcat 服务器 webapps 目录下自带了几个项目,这些项目当中都有 web.xml,可以从这里拷贝样例文件。
在 web01\WEB-INF\目录下新建 web.xml文件,进行以下的配置:
xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0"
metadata-complete="true">
<servlet>
<servlet-name>firstServlet</servlet-name>
<servlet-class>com.jkweilai.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>firstServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
需要引起注意:
**metadata-complete="true"**:容器忽略所有注解,只使用 web.xml 配置
<font style="color:rgb(15, 17, 21);">metadata-complete="false"</font>(默认值):容器会扫描注解
7.5 部署项目到 Tomcat
将 web01目录拷贝到 CATALINA_HOME/webapps目录下,如下:

启动 Tomcat 打开浏览器访问
浏览器上的结果:

控制台的结果:

7.6 使用超链接发送请求
在上面测试时,浏览器地址栏上直接输入的地址是:http://localhost:8080/web01/hello,也可以采用用户点击超链接的方式发送请求。在 web01目录下新建 index.html。然后编写如下代码:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页</title>
</head>
<body>
<a href="http://localhost:8080/web01/hello">hello1</a>
<!--http://ip:port 可以省略。前端编写的路径目前都以 / 开头,并且一定要添加项目名。-->
<a href="/web01/hello">hello1</a>
</body>
</html>
将 index.html文件部署到 Tomcat 服务器的 web01项目下:

再次启动服务器测试
启动 Tomcat 服务器,然后打开浏览器在地址栏上输入:http://localhost:8080/web01/index.html

点击以上两个超链接发送请求,结果都是:

将 index.html 放到 WEB-INF 目录下测试

启动服务器,打开浏览器,输入地址:http://localhost:8080/web01/WEB-INF/index.html,如下:

通过测试得知,放在 WEB-INF 目录下的资源是受保护的。
7.7 响应一段中文到浏览器
修改 HelloServlet.java中的代码,响应一段中文到浏览器。修改代码之后,保存,然后重新编译,将新生成的代码重新拷贝到 Tomcat 服务器的 web01/WEB-INF/classes目录下,最后启动 Tomcat 服务器,打开浏览器访问。
java
public void service(ServletRequest request,ServletResponse response)
throws ServletException, IOException{
// 向控制台打印
System.out.println("Hello Servlet!");
// 向浏览器上响应HTML
PrintWriter out = response.getWriter();
out.print("<h1>Hello Servlet!</h1>");
out.print("<h1>你好,服务器端的小程序!</h1>");
}
运行效果:

发现响应中文的时候出现了乱码问题,编写以下代码来解决响应时的中文乱码问题:
java
public void service(ServletRequest request,ServletResponse response)
throws ServletException, IOException{
// 向控制台打印
System.out.println("Hello Servlet!");
// 向浏览器上响应HTML
response.setContentType("text/html"); // 设置响应的内容类型,这个对解决响应时的中文乱码问题没有作用。
response.setCharacterEncoding("UTF-8"); // 设置响应时采用的字符编码方式。这个是解决响应时中文乱码问题的关键。
PrintWriter out = response.getWriter();
out.print("<h1>Hello Servlet!</h1>");
out.print("<h1>你好,服务器端的小程序!</h1>");
}
重新编译、重新部署、重启服务器访问:

中文乱码问题就解决了。另外,以上解决中文乱码的两行代码:
java
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
可以合并为一行:
java
response.setContentType("text/html;charset=UTF-8");
**注意:这行代码必须出现在 ****PrintWriter out = response.getWriter();**之前才能解决乱码问题。
**<font style="color:#DF2A3F;">response.setCharacterEncoding("UTF-8");</font>**和 HTML 中的 **<font style="color:#DF2A3F;"><meta charset="UTF-8"></font>**有什么区别?
- 前者:设置Servlet输出流的字符编码方式,影响
**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">PrintWriter</font>**如何将Java字符串转换为字节序列,是服务器端的行为,发生在内容发送到客户端之前,会自动设置**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">Content-Type</font>**响应头的charset部分,例如:**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">Content-Type: text/html;charset=UTF-8</font>**这是最根本的编码设置,决定了数据在传输时的实际编码。 - 后者:是HTML文档内部的编码声明,浏览器在解析HTML时会参考这个提示,当HTTP响应头没有指定charset时,浏览器会查找meta标签,如果HTTP头已指定charset,meta标签通常会被忽略。
8. Servlet 连接数据库
继续在 web01项目中实现连接数据库的效果。实现功能:以列表形式显示部门名称。
8.1 添加 mysql 驱动
在 WEB-INF目录下新建 lib目录,将 mysql.jar驱动放到 lib目录中。

8.2 编写 DeptListServlet
java
package com.jkweilai.servlet;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.ServletConfig;
import java.io.PrintWriter;
import java.io.IOException;
import java.sql.*;
public class DeptListServlet implements Servlet{
public void init(ServletConfig config) throws ServletException{}
public void service(ServletRequest request,ServletResponse response)
throws ServletException, IOException{
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
// 1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.获取连接
String url = "jdbc:mysql://localhost:3306/servlet";
String user = "root";
String password = "123456";
conn = DriverManager.getConnection(url, user, password);
// 3.获取预编译的数据库操作对象
String sql = "select dname from dept";
ps = conn.prepareStatement(sql);
// 4.执行SQL
rs = ps.executeQuery();
// 5.处理查询结果集
while(rs.next()){
String dname = rs.getString("dname");
out.print(dname);
out.print("<br>");
}
}catch(Exception e){
e.printStackTrace();
}finally{
// 6.释放资源
if(rs != null){
try{
rs.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(ps != null){
try{
ps.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(conn != null){
try{
conn.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
public void destroy(){}
public String getServletInfo(){
return "";
}
public ServletConfig getServletConfig(){
return null;
}
}
编译后,将编译后的字节码拷贝到 WEB-INF/classes目录下,这里不再赘述。
8.3 编写 web.xml
xml
<servlet>
<servlet-name>dListServlet</servlet-name>
<servlet-class>com.jkweilai.servlet.DeptListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dListServlet</servlet-name>
<url-pattern>/list</url-pattern>
</servlet-mapping>
8.4 提供超链接
在 index.html文件中添加超链接:
html
<!--对于前端请求路径目前以 / 开始,带项目名。web.xml文件中的路径不带项目名。-->
<a href="/web01/list">部门列表</a>
8.5 部署测试
将项目部署到 Tomcat 的 webapps 目录下,启动 Tomcat 服务器,打开浏览器输入地址:http://localhost:8080/web01/index.html

点击部门列表超链接发送请求:

9. IDEA 开发 Servlet
9.1 创建空项目

设置空项目的 JDK 版本:

9.2 创建普通 java 模块

9.3 创建 web 目录作为 webapproot

9.4 添加 web 支持

添加 web.xml文件时,选择 6.0版本。
9.5 添加 Artifact(构件)
Artifact 是构件的意思,通常指代** 可部署的输出文件**。

将 servlet-api.jar 添加到 classpath 中
注意,这个 jar 包只是起到一个编译阶段的作用(只是让我们在 IDEA 中编写的 Servlet 程序能够正常编译),因此这个 jar 包不需要放到 WEB-INF/lib目录中。因为 WEB-INF/lib目录下的 jar 包是在运行阶段起作用的,Tomcat 服务器运行时 servlet-api.jar 已经在 CATALINA_HOME/lib目录下了。
在 web01模块下随意创建一个目录,例如 lib,然后将 servlet-api.jar拷贝到该目录下,然后 右键-->Add as Library...

9.6 添加数据库驱动
在 WEB-INF目录下新建 lib目录,将 mysql 驱动 jar 包拷贝到该目录下:

这个 jar 包是在运行阶段起作用的,编译阶段不需要。
9.7 编写 Servlet 和 web.xml
使用之前的 DeptListServlet程序即可。
xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<servlet>
<servlet-name>listServlet</servlet-name>
<servlet-class>com.jkweilai.servlet.DeptListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>listServlet</servlet-name>
<url-pattern>/list</url-pattern>
</servlet-mapping>
</web-app>
9.8 IDEA 配置 Tomcat

9.9 部署构件到 Tomcat

**上图当中的 ****On 'Update' action**是指定什么的?
- 它是用来:当你手动触发"更新"操作时,IDEA 应该对正在运行的 Tomcat 应用执行什么动作。
- 怎么手动触发"更新"操作?当我们修改了项目代码之后,需要更新应用,代码才能生效,通过
<font style="color:rgb(15, 17, 21);">ctrl + F10</font>可以手动触发应用更新。或者点击下图面板上的刷新按钮,也能够触发应用更新

- 执行的动作包括:

Update resources表示仅更新静态资源。
Update classes and resources表示既更新静态资源又更新字节码。
Redeploy表示整个 web 项目重新部署。
Restart server表示重启 web 服务器。
**上图当中的 ****On frame deactivation**是指定什么的?
- 当你把 IDEA 窗口切换到其他应用程序(即 IDEA 失去焦点)时,IDEA 自动执行什么操作。
- 一般建议设置为
<font style="color:rgb(15, 17, 21);">Do nothing</font>,除非你电脑的配置很好。
9.10 启动 Tomcat 测试

启动成功,但控制台有中文乱码,这是因为当前版本的 IDEA 控制台的默认字符编码方式为 UTF-8(看下图可以查看控制台的字符编码方式) ,需要将 CATALINA_HOME/conf/logging.properties文件中之前的修改的 GBK,再次改回 UTF-8即可:

打开浏览器访问:http://localhost:8080/web01/list

10. HTTP协议
10.1 什么是HTTP协议
HTTP(HyperText Transfer Protocol,超文本传输协议) 是一种用于分布式、协作式超媒体信息系统的应用层协议。它是万维网(WWW)数据通信的基础,基于客户端-服务器模型,通过请求-响应模式工作。
核心特点:
- 无状态:默认不保留之前的请求/响应信息(可通过Cookie/Session实现状态管理)。
- 基于TCP/IP:默认端口80(HTTPS为443)。
- 灵活可扩展:支持自定义头部、多种数据格式(JSON、XML等)。
HTTP 协议版本:
- HTTP/1.0:短连接。每次浏览器向服务器发起一个请求,都会建立一个全新的 TCP 连接。
- HTTP/1.1:持久连接。浏览器和服务器建立一次 TCP 连接后,可以在这个连接上连续进行多次请求和响应。
HTTP1.1 连接是可复用的:
- 对同一域名的请求,可以复用同一个连接
- 例如有这样一个网页:在 HTTP/1.1 时代,浏览器通常为每个域名开启 6 个左右的并行连接,以下页面在加载的时候就会有连接复用的情况。(底层弄了个 TCP 连接池,连接池最高支持 6 个 TCP 连接并发,下面这个 HTML 页面需要 9 个 TCP 连接,1 个加载 HTML,8 个加载图片。因此有连接复用的情况)
html
<body>
<img src="http://localhost:8080/app/1.jpg">
<img src="http://localhost:8080/app/2.jpg">
<img src="http://localhost:8080/app/3.jpg">
<img src="http://localhost:8080/app/4.jpg">
<img src="http://localhost:8080/app/5.jpg">
<img src="http://localhost:8080/app/6.jpg">
<img src="http://localhost:8080/app/7.jpg">
<img src="http://localhost:8080/app/8.jpg">
</body>
HTTP/1.1 是有状态的吗?
- 无状态。尽管从 1.0 的短连接升级成了 1.1 的持久连接,但 HTTP 协议仍然是无状态的。无状态主要体现在:默认不保留之前的请求/响应信息。
10.2 HTTP请求报文详解
HTTP请求报文由以下部分组成:
http
GET /index.html?name=value&name=value HTTP/1.1 # 请求行(方法 + URI + 协议版本)
Host: www.example.com # 请求头部(键值对)
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml
Accept-Language: en-US
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Cookie: sessionId=abc123; userId=admin
# 空行(分隔头部和体)
name=John&age=30 # 请求体(GET通常无体,POST/PUT等有)
关键字段说明:
- 请求行 :
- 方法:GET(获取资源)、POST(提交数据)、PUT(更新)、DELETE(删除)等。
- URI :请求的资源路径(如
/index.html)。 - 协议版本:HTTP/1.1 或 HTTP/2。
- 请求头部 :
Host:目标服务器域名(必填)。User-Agent:客户端标识(如浏览器类型)。Content-Type:请求体的数据类型(application/x-www-form-urlencoded表示普通表单提交,application/json表示以 JSON 格式提交数据)。Cookie:客户端携带的会话信息。
- 请求体:仅POST/PUT等方法携带数据(如表单、JSON)。
10.3 HTTP响应报文详解
HTTP响应报文结构:
http
HTTP/1.1 200 OK # 状态行(协议版本 + 状态码 + 描述)
Server: nginx/1.18.0 # 响应头部
Date: Mon, 01 Jun 2025 12:00:00 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 1234
Connection: keep-alive
Set-Cookie: session_id=abc123; HttpOnly; SameSite=Strict
# 空行
<!DOCTYPE html> # 响应体(实际数据)
<html>...</html>
关键字段说明:
- 状态行 :
- 状态码 :
**<font style="color:#DF2A3F;">200 OK</font>**:成功。**<font style="color:#DF2A3F;">404 Not Found</font>**:资源不存在。**<font style="color:#DF2A3F;">405</font>**:请求方式和服务器端的处理方式不一致。(例如:前端请求方式为 POST,服务器端处理方式是 GET,则发生 405 错误。)**<font style="color:#DF2A3F;">500 Internal Server Error</font>**:服务器错误。
- 状态码 :
- 响应头部 :
Content-Type:响应体类型(如text/html、application/json)。Content-Length:响应体大小(字节)。Set-Cookie:服务器设置的会话标识。【HttpOnly设置在浏览器不能使用 document.cookie 读取,防止 XSS 攻击。 SameSite=Lax允许部分安全的跨站请求(如导航链接),SameSite=Strict最严格,完全禁止在跨站请求中发送Cookie】
- 响应体:返回的实际数据(HTML、JSON等)。
10.4 GET与POST的区别及选择
10.4.1 区别
| 特性 | GET请求 | POST请求 |
|---|---|---|
| 数据位置 | URL查询参数(如?name=John) |
请求体中(不可见) |
| 数据长度限制 | 受URL长度限制(约2048字符) | 无限制(服务器可配置) |
| 安全性 | 参数暴露在URL,不适合敏感数据 | 相对更安全(HTTPS下加密) |
| 幂等性 | 幂等(多次请求结果相同) | 非幂等(可能修改数据) |
| 缓存 | 可被缓存 | 默认不缓存 |
| 浏览器历史记录 | 保留参数 | 不保留 |
**幂等性 **就是:同一个操作,你执行1次和执行N次,结果都一样。
**幂等 **操作:你按电梯的"关门"按钮,按1次和疯狂按10次,效果都一样------门只会关一次。
非幂等操作:你喝奶茶,每点一次"加珍珠"按钮,杯子里就多一份珍珠(点10次就爆炸了)。
提示:GET 和 POST 请求提交数据时的格式都是 **<font style="color:#DF2A3F;">name=value&name=value&name=value...</font>**。只是提交数据的位置不同,GET 在请求行上提交数据。POST 在请求体中提交数据。
10.4.2 如何选择
- 用GET :
- 获取数据(如搜索、页面加载)。
- 参数简单且非敏感(如分页
?page=2)。
- 用POST :
- 提交敏感数据(如登录表单、支付信息)。
- 上传文件或大量数据(如JSON body)。
- 修改服务器状态(如创建/更新资源)。
10.4.3 怎么发送 POST 请求
到目前为止,浏览器向服务器发送请求时,我们所掌握的所有的方式包括:
- 用户在浏览器地址栏上直接输入 URL
- 用户点击超链接
- 使用 window.location.href 或 document.location.href
- 使用 window.open
- 用户提交 form 表单
- 使用
img的src属性也可以发送请求:GET 请求
以上所有的方式中,只有当使用 form表单提交数据,并且 form标签的 method属性设置为 post时,才是 POST请求,其它都是 GET 请求。
10.5 URL编码
URL编码(也称为百分号编码)是HTTP协议和Web开发中一个非常重要的概念。
B/S 系统通信标准中规定 :URL 字符串中只允许出现 ASCII 字符集之内的字符。非 ASCII 字符(如:中文)在传输中都可能被错误的解析。
不过大家不需要担心,大部分的请求发送都已经自动对 URL 进行了编码,只有少数情况需要手动编码。
只要有 URL,就一定涉及到 URL 的编码和解码,前端系统需要,后端系统也需要。
10.5.1 URL编码的作用
URL编码主要用于:
- 解决特殊字符问题:URL中某些字符有特殊含义(如?、&、/等),当这些字符需要作为普通字符使用时必须编码
- 支持非ASCII字符:URL只能使用ASCII字符集,非ASCII字符(如中文)必须编码,防止数据在传输过程中被错误解析
10.5.2 前端系统中什么情况下需要手动编码
浏览器只在"用户交互触发的导航"(如地址栏输入、点击链接、表单提交)时自动编码;
在"JavaScript 程序化地拼接和操作 URL"时,不会自动编码,需要开发者手动 encodeURIComponent。
以下情况都会自动编码:
- 直接在地址栏输入中文:浏览器会自动进行编码。
- 点击跳转:浏览器会对查询参数自动编码。
- 表单 GET 提交:浏览器会自动对表单字段进行 URL 编码。
以下情况需要手动编码:
- AJAX 请求中,手动拼接 URL 参数时
- 使用 window.location.href 进行页面跳转时
- history.pushState 或 replaceState 改变 URL 时
前端系统对 URL 进行编码解码的 API 是: **encodeURIComponent() / decodeURIComponent()**
10.5.3 后端系统中什么情况下需要手动编码
后端系统中,以下三种情况都需要手动编码 ,其他情况都不需要。
第一种情况:重定向时的 URL 参数需要手动编码。
java
String redirectUrl = "/search?q=" + URLEncoder.encode(userInput, "UTF-8");
response.sendRedirect(redirectUrl);
第二种情况:Cookie 的值需要手动编码。【其实这个和 URL 就没什么关系了,属于 HTTP 协议的一部分】
第三种情况:自定义响应头的值需要手动编码。【其实这个和 URL 也没什么关系了,属于 HTTP 协议的一部分】
后端系统手动编码/解码的 API 如下:
java
String original = "搜索 关键词&特殊字符";
String encoded = URLEncoder.encode(original, "UTF-8");
// 手动编码
// %E6%90%9C%E7%B4%A2+%E5%85%B3%E9%94%AE%E8%AF%8D%26%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6
System.out.println(encoded);
// 手动解码
// 搜索 关键词&特殊字符
String decoded = URLDecoder.decode(encoded, "UTF-8");
System.out.println(decoded);