javaweb--08

一、乱码产生的根本原因

HTTP 传输中,中文会经过URL 编码 与解码两个环节,编码 / 解码格式不匹配就会产生乱码:

  1. 浏览器端 :将中文按 UTF-8 编码为二进制,再转为 %E5%BC%A0%E4%B8%89 格式的 URL 编码串
  2. Tomcat 端 :默认按 ISO-8859-1(单字节编码,不支持中文)进行 URL 解码,导致中文被错误解析为乱码(如 å¼ ä¸‰)

二、分请求方式的解决方案

1. POST 请求(最常用,方案简单)

POST 请求的参数在请求体 中,通过 getReader() 字符流读取,直接设置输入流编码即可解决:

java

运行

复制代码
// 必须在获取参数前调用!
request.setCharacterEncoding("UTF-8");

// 再获取参数
String username = request.getParameter("username");
System.out.println(username);
  • 核心要求 :必须在第一次获取参数前调用该方法,否则设置无效
  • 原理 :统一请求体的解码格式为 UTF-8,与浏览器编码格式一致,从根源解决乱码

2. GET/POST 通用方案(兼容所有请求方式)

适用于 GET 请求(参数在 URL 中,setCharacterEncoding 对 GET 无效),或需要统一处理所有请求的场景:

java

运行

复制代码
// 1. 先按ISO-8859-1获取字节(还原Tomcat的错误解码)
String username = request.getParameter("username");
// 2. 用UTF-8重新编码,还原正确中文
username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
  • 原理 :先将乱码字符串按 ISO-8859-1 转回原始字节,再用 UTF-8 正确解码,彻底解决编码不匹配问题
  • 兼容性:对 POST 请求同样有效,可作为全局通用方案

三、URL 编码与解码原理

1. URL 编码规则

  1. 将字符串按指定编码(如 UTF-8)转为二进制字节
  2. 每个字节转为 2 个 16 进制数,并在前面加上 %
    • 示例:张三 → UTF-8 编码 → %E5%BC%A0%E4%B8%89

2. Java 手动编码 / 解码 API

java

运行

复制代码
import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

// 1. 编码(浏览器端逻辑)
String str = "张三";
String encodedStr = URLEncoder.encode(str, StandardCharsets.UTF_8);
// 结果:%E5%BC%A0%E4%B8%89

// 2. 解码(Tomcat端逻辑)
String decodedStr = URLDecoder.decode(encodedStr, StandardCharsets.UTF_8);
// 结果:张三
  • 注意 :Tomcat 8+ 已默认将 GET 请求的 URL 解码格式改为 UTF-8,GET 乱码问题在高版本 Tomcat 中已自动解决,仅需处理 POST 请求

四、完整实战示例(Servlet 中处理乱码)

java

运行

复制代码
@WebServlet("/encoding-demo")
public class EncodingServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 方案1:POST专用,优先使用
        request.setCharacterEncoding("UTF-8");
        String username = request.getParameter("username");
        System.out.println("POST方式获取:" + username);

        // 方案2:GET/POST通用,兼容所有场景
        String username2 = request.getParameter("username");
        username2 = new String(username2.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
        System.out.println("通用方式获取:" + username2);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // GET请求直接用通用方案
        String username = request.getParameter("username");
        username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
        System.out.println("GET方式获取:" + username);
    }
}
相关推荐
拆房老料1 小时前
【第四部分:Agentic 智能体设计模式】16. 一个 Prompt 搞不定复杂任务?试试 Prompt Chaining
java·前端·人工智能·设计模式·prompt
曹牧7 小时前
C#:空合并运算符
java·前端·数据库
小羊没烦恼!7 小时前
铁道部新客票系统设计(二)
开发语言·前端·数据库·python·oracle·c#·php
智能直播10 小时前
RK3518:1.5G 内存 + 8G 存储,如何跑起硬件编解码、Web、AI 识别、绿幕特效
前端·人工智能·5g
掘金酱11 小时前
【10.24 特别活动】AI 时代,程序员的新饭碗在哪里?
前端·人工智能·后端
excel11 小时前
多进程环境下使用 PM2 部署 Socket.IO:需要注意什么
前端
IT_陈寒12 小时前
Redis的原子性竟然失效了?记一次分布式锁翻车实录
前端·人工智能·后端
时间的情敌13 小时前
《回顾 2018 前端:Vue2 成熟期,Webpack4 发布,PWA 大火》
前端
Java后端的Ai之路14 小时前
前端技术Vue-09-webpack-vuejs-实战
前端·vue.js·webpack
LMT流氓兔14 小时前
第五单元——第4课:给工具参数加校验
java·前端·算法·ai·langchain