老生常谈--关于J2EE开发中的字符编码

本文详细介绍了UTF-8编码在Web开发中的应用,包括JSP页面设置、Struts2及Servlet处理请求参数的方法,确保多字节字符串正确展示。

这几天发现团队中的几个新成员对于开发中的编码理解的不是很好,特意写这篇文章,帮助大家理解。


首先,我们明确我们的目标在我们的工程中全部使用UTF-8编码。

其次,我们需要了解开发中解除到的编码包括文件内容编码、请求参数编码、返回内容编码。


文件内容编码

首先我们讨论文件内容编码。jsp页面是我们MVC模式中的View,是展现到前台的页面,所以这个页面必须要支持多字节字符串(日常主要是中文),我们必须为其设置编码格式。

我们先看一个简单的jsp示例文件:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>中文页面</title>
</head>
<body>
<h1>您好,这个页面支持中文。</h1>
</body>
</html>

注意:

  1. 每个JSP文件的pageEncoding是基础,只有你设置了这个,tomcat在请求过来时将JSP文件转换为java文件(servlet源文件)的时候才会将其转换为非乱码格式,否则如果你将pageEncoding设置为US-ASCII,文件中的中文都会是乱码了;
  2. JSP头部的contentType和html部分的meta中的Content-Type其实是一回事,都是设置最后展现的时候告诉浏览器这个页面的字符集,如果这里指定的字符集浏览器中没有安装,正常情况下浏览器会提示去安装,和具体显示不太搭界。
  3. contentType中的charset还有个作用就是设置我们的请求响应的编码,也就是说,如果我们提交请求的时候使用的编码格式不正确,那么最后输出的结果可能也不正确,具体在servlet中我们可以通过pageContext.getResponse().getCharacterEncoding()得到这些值;

所以按照以上理论,正常情况下我们只需要设置pageEncoding就可以了,但为了支持有些用户使用的英文系统,为了提示使用者去下载中文支持,需要添加contentType。


请求参数编码

struts中使用

首先我们看一下struts2中如何使用字符编码。我们建立一个简单的struts2工程,写一个DummyAction:

package com.freesoft.action;

import com.opensymphony.xwork2.ActionSupport;

public class DummyAction extends ActionSupport {

	/**
	 * 
	 */
	private static final long serialVersionUID = -9106994256206918756L;

	private String username;
	private String password;
	private Integer age;
	
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	
	@Override
	public String execute() throws Exception {
		System.out.println("username is " + username);
		System.out.println("password is " + password);
		System.out.println("age is " + age);
		return SUCCESS;
	}
}

我们的请求页面是:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>中文网页</title>
</head>
<body>
<h1>中文网页测试</h1>
<s:form action="dummy.action">
	<s:textfield name="username" label="username"></s:textfield>
	<s:textfield name="password" label="password"></s:textfield>
	<s:textfield name="age" label="age"></s:textfield>
	<s:submit value="submit"></s:submit>
</s:form>
</body>
</html>

结果页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<s:label value="%{username}"></s:label>
</body>
</html>

我们在请求中输入中文的名字,发现可以正确处理中文。那么我们再去深入,当你在你的struts.xml配置文件的package外面加上:

<constant name="struts.i18n.encoding" value="US-ASCII"></constant>
的时候,再去使用中文名,就会出现乱码,说明是i18n这个interceptor中的encoding属性设定了字符编码格式。我们去源码中也可以很清楚的看到默认的编码格式设置的是在org.apache.struts2.dispatcher.Dispatcher文件中使用注解方式注入。文件default.properties中就设置了这个值:

### This can be used to set your default locale and encoding scheme
# struts.locale=en_US
struts.i18n.encoding=UTF-8

所以我们可以自己去覆盖这个值。


Servlet方式

好了,struts方式搞定了之后能够保证我们的工作不出问题,下面我们随便讲讲servlet工作的流程:

servlet默认情况下是不会处理字符编码的,所以在request和response中都要你自己设置,我们看一下源代码(原来在tomcat/webapp下面的,从tomcat 7.0.20就转移到tomcat自己的源码中了,所以还需要下载一个tomcat源代码),这个类:org.apache.catalina.filters.SetCharacterEncodingFilter。



让我们再看看Tomcat给的建议,保证你在所有地方都是用UTF-8:

  1. 在server.xml的Connector中设置URIEncoding="UTF-8",类似于这种:
    <Connector port="8090" maxThreads="150" minSpareThreads="25" 
    maxSpareThreads="75"
    enableLookups="false" redirectPort="8443" acceptCount="100"
    debug="0" connectionTimeout="20000"
    disableUploadTimeout="true"
    URIEncoding="UTF-8"/>

  2. 使用一个filter来使得编码转换为UTF-8,可以使用Tomcat提供的这个;
  3. 在jsp中设置contentType使用UTF-8;
  4. 使response的输出都使用UTF-8,也就是使用:
    response.setContentType("text/html; charset=UTF-8")
    或者
    response.setCharacterEncoding("UTF-8")
  5. 你使用的任何会产生内容的库(例如Velocity, Freemarker,等等)中的编码设置都设置为UTF-8。
  6. 在所有可能读取参数的情况之前加载你的编码转换Filter;




<think>嗯,用户这次问的是前端开发中的常见难题及解决方案,还特意提供了5篇站内引用资料。从对话历史看,用户之前对鸿蒙开发的问题很关注,现在转向更通用的前端领域,可能是想拓宽技术视野。 用户给的参考资料质量参差不齐,需要筛选核心信息:引用[1]强调前端知识面广导致问题多,引用[2]聚焦Vue.js特定问题,引用[3]讲浏览器兼容性,引用[4]讨论性能优化,引用[5]详解跨域方案。综合来看,用户需要的是覆盖主流痛点的系统解决方案。 注意到用户特别标注"不是真正需求",说明ta更期待实际案例而非理论堆砌。上次回答鸿蒙问题时采用的"问题描述+解决方案+代码示例"结构效果不错,这次可以延续。需要重点突出三个维度:浏览器兼容性(约占前端bug的40%)、性能优化(直接影响用户体验)、框架特定问题(Vue/react生态差异)。 跨域问题虽然引用[5]讲得很透,但属于老生常谈,考虑放在"其他挑战"里简写,重点补充现代前端工程化问题(如Webpack配置)这类更头疼的难题。对于解决方案,要强调可操作性——比如提到PostCSS时具体说明autoprefixer插件的用法。 最后生成的"相关问题"特意加入TypeScript和微前端,这是观察用户技术倾向后的设计:既然ta关注鸿蒙这种新框架,应该对前沿架构感兴趣。安全策略则延续了ta上次对鸿蒙安全特性的追问习惯。</think>以下是前端开发中常见难题及解决方案的深度解析,结合主流技术栈和工程实践: --- ### 一、浏览器兼容性问题 #### 核心痛点 - **渲染差异**:不同浏览器对CSS/JS解析不一致(如IE盒模型、Flex布局支持)[^3] - **特性支持滞后**:新API(如ES2021、WebGL2)在旧浏览器不可用 - **前缀要求**:需添加`-webkit-`、`-moz-`等前缀 #### 解决方案 1. **渐进增强策略** ```css /* 先写标准属性 */ .box { border-radius: 8px; } /* 再覆盖浏览器前缀 */ -webkit-border-radius: 8px; -moz-border-radius: 8px; ``` 2. **自动化工具链** - 使用`PostCSS` + `autoprefixer`自动补全前缀 - 配置`.browserslistrc`定义兼容范围: ``` last 2 versions not IE < 11 ``` 3. **Polyfill按需注入** ```html <!-- 条件加载polyfill --> <script> if (!Promise) { document.write('<script src="polyfill.min.js"><\/script>'); } </script> ``` --- ### 二、性能优化难题 #### 关键瓶颈 - 首屏加载慢(资源体积过大) - 交互卡顿(长列表渲染、频繁重排) - 内存泄漏(SPA常见问题) #### 优化方案 | 问题类型 | 解决方案 | 工具示例 | |-----------------|-----------------------------------|--------------------------| | **资源加载** | 代码分割 + 懒加载 | `React.lazy()` + `Suspense` | | **渲染阻塞** | 关键CSS内联 + 异步加载非核心JS | `critical` npm包 | | **长列表** | 虚拟滚动 | `react-window` / `vue-virtual-scroller` | | **重绘优化** | 使用`transform`替代`top/left` | CSS硬件加速 | | **内存泄漏** | 销毁事件监听 + 清理定时器 | `useEffect`清理函数 | **实战案例**:优化图片加载 ```javascript // 图片懒加载 const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; observer.unobserve(img); } }); }); document.querySelectorAll('.lazy-img').forEach(img => observer.observe(img)); ``` --- ### 三、跨域问题(CORS) #### 常见场景 - 本地开发`localhost`调用生产API - 多子域名资源共享(`a.com` → `api.a.com`) - 第三方服务集成(如地图API) #### 解决方案 1. **服务端配置CORS** ```http Access-Control-Allow-Origin: https://your-domain.com Access-Control-Allow-Methods: GET,POST ``` 2. **开发环境代理**(Vite示例) ```js // vite.config.js export default { server: { proxy: { '/api': { target: 'http://backend-service', changeOrigin: true } } } } ``` 3. **JSONP备选方案** ```html <script> function handleResponse(data) { console.log(data); } </script> <script src="https://api.example.com/data?callback=handleResponse"></script> ``` --- ### 四、框架特定问题(以Vue为例) #### 高频问题集 1. **响应式数据失效** - **场景**:直接给数组索引赋值/对象新增属性 - **解决**: ```js // Vue2 this.$set(this.list, index, newValue) // Vue3 import { set } from 'vue' set(obj, 'newProp', 123) ``` 2. **状态管理混乱** - **反模式**:在多个组件直接修改Vuex状态 - **最佳实践**: ```js // 使用actions异步提交 actions: { async fetchData({ commit }) { const res = await api.getData(); commit('SET_DATA', res.data); } } ``` 3. **生命周期钩子误用** - **典型错误**:在`created`中操作DOM - **纠正**: ```js mounted() { // 此时DOM已渲染完成 this.$refs.container.addEventListener(...) } ``` --- ### 五、工程化挑战 #### 痛点及对策 1. **构建速度慢** - 使用`esbuild`替代Babel(Vite核心原理) - 开启缓存:`webpack.cache: { type: 'filesystem' }` 2. **部署后资源404** - 配置publicPath: ```js // vue.config.js module.exports = { publicPath: process.env.NODE_ENV === 'production' ? '/your-subpath/' : '/' } ``` 3. **环境变量管理** - 使用`.env`文件分级: ``` .env # 全局默认 .env.local # 本地覆盖(gitignore) .env.prod # 生产环境 ``` --- ### 六、安全防护 #### 必做措施 1. **XSS防御** - 输入过滤 + 输出转义 - 使用`textContent`替代`innerHTML` - 开启CSP: ```http Content-Security-Policy: default-src 'self' ``` 2. **CSRF防护** - 同源检测(SameSite Cookie) - 添加Token验证: ```html <meta name="csrf-token" content="{{ csrf_token() }}"> ``` ```js axios.defaults.headers.common['X-CSRF-TOKEN'] = token ``` --- ### 总结建议 前端开发需建立**分层防御体系**: 1. **基础层**:浏览器兼容性工具链(PostCSS+Babel) 2. **性能层**:加载优化(代码分割/懒加载) + 渲染优化(虚拟化) 3. **架构层**:状态管理规范化 + 组件解耦 4. **安全层**:XSS/CSRF防御 + HTTPS强制 > 最新趋势:使用`LightHouse`自动化评分、`Web Vitals`监控核心指标、`TypeScript`强化代码健壮性[^2][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值