使用Docker部署tomcat,出现中文名文件无法读取,访问就是404错误。在网上搜索一通,都说是在tomcat的配置文件server.xml中修改一下URIEncoding为utf-8就行,但是我怎么测试都不行。最终发现,是Docker启动时,传入了环境变量LANG="zh_CN.UTF-8"导致。
先说网上通用处理方式。在tomcat根目录的conf文件夹下,修改server.xml文件,增加URIEncoding="UTF-8"配置。变成如下:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
URIEncoding="UTF-8" useBodyEncodingForURI="true"
redirectPort="8443" />
但是我测试后,还是不行。中文文件访问,依然是无法找到文件,404错误。
继续寻找各种资料和解决方案,都不行。继续折腾好久,仍然没有解决。网上说的各种都试过。
最后,想想是不是tomcat版本问题。
于是用Docker启动一个最新版本的tomcat 11,啥环境变量和文件映射都不做,一测试,居然没问题。也就是tomcat 11默认就是支持中文文件名。
那么全新的tomcat9呢?什么环境变量和文件映射都不做,一测试,居然也行。原来tomcat本身是没有问题的,问题出在启动容器时的传参。现在采用排除法,找到问题参数。
当前启动传参如下。
docker run -it --name tomcat-test --rm -p 8888:8080 \
-e TZ="Asia/Shanghai" \
-e LANG="zh_CN.UTF-8" \
-e JAVA_OPTS="-Dfile.encoding=utf-8" \
tomcat:9.0.16-jre8
逐一排查后,发现传参-e LANG="zh_CN.UTF-8"后,会导致file.encoding变成ANSI_X3.4-1968,而不是默认的UTF-8。
写个test.jsp文件,拷贝到容器内tomcat的ROOT目录下,直接访问,输出一下各种参数。
<%@ page language="java" contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.TimeZone" %>
<%@ page import="javax.servlet.ServletContext" %>
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>容器环境测试测试</title>
</head>
<body>
<%
// 获取当前时间
Date currentDate = new Date();
// 获取当前时区
TimeZone timeZone = TimeZone.getDefault();
// 获取ServletContext对象
ServletContext context = request.getServletContext();
// 获取当前JSP页面的真实路径
String realPath = context.getRealPath("/");
String contextPath = context.getContextPath();
String serverInfo = context.getServerInfo();
String virtualServerName = context.getVirtualServerName();
%>
<p>当前时间:<%= currentDate.toString() %></p>
<p>当前时区: <%= timeZone.getDisplayName() %></p>
<p>物理路径RealPath: <%= realPath %></p>
<p>环境路径ContextPath: <%= contextPath %></p>
<p>服务端容器: <%= serverInfo %></p>
<p>虚拟服务名称: <%= virtualServerName %></p>
<p>当前字符集编码file.encoding: <%= System.getProperty("file.encoding") %></p>
<p>Java环境变量java.opts: <%= System.getenv("JAVA_OPTS") %></p>
<p>Java环境变量sun.jnu.encoding: <%= System.getProperty("sun.jnu.encoding") %></p>
</body>
</html>
输出结果,如下图所示。 文本编码不是UTF-8,变成了ANSI_X3.4-1968。
当启动容器时,去掉该环境变量传入,就可以识别中文名文件了。
由于这个问题折腾了太久,暂时也就不想去深究为什么。想想这个LANG变量对目前功能没啥影响,就先不传入了吧。后面遇到影响了再说。