当前位置: 首页 > news >正文

java.lang.IllegalArgumentException: 在请求目标中找到无效字符。有效字符在RFC 7230和RFC 3986中定义

 Tomcat 屏蔽错误信息。java.lang.IllegalArgumentException: 在请求目标中找到无效字符。有效字符在RFC 7230和RFC 3986中定义

<h1>HTTP状态 400 - 错误的请求</h1>
	<hr class="line" />
	<p><b>类型</b> 异常报告</p>
	<p><b>消息</b> 在请求目标中找到无效字符。有效字符在RFC 7230和RFC 3986中定义</p>
	<p><b>描述</b> 由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求。</p>
	<p><b>例外情况</b></p>
	<pre>java.lang.IllegalArgumentException: 在请求目标中找到无效字符。有效字符在RFC 7230和RFC 3986中定义
	org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:512)
	org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:503)
	org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:831)
	org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1631)
	org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	java.lang.Thread.run(Thread.java:750)

简介

在开发和生产环境中,出于安全和隐私的考虑,我们可能不希望将详细的错误信息暴露给用户。Tomcat 提供了一种机制,允许我们通过配置 ErrorReportValve 来控制错误报告的显示。本文将详细介绍如何在 Tomcat 的 server.xml 文件中配置 ErrorReportValve,以屏蔽错误报告和服务器信息。

为什么需要屏蔽错误报告?

  1. 安全考虑:错误报告可能包含敏感信息,如数据库连接字符串、系统路径等,这些信息如果被恶意用户获取,可能会对系统安全造成威胁。

  2. 用户体验:对于最终用户来说,看到详细的错误信息可能会引起困惑或不安。提供一个友好的错误页面可以改善用户体验。

  3. 避免信息泄露:在生产环境中,错误报告可能会泄露系统的内部工作原理,这可能会被恶意用户利用。

如何配置 Tomcat 屏蔽错误报告

步骤 1:打开 server.xml 文件

server.xml 文件通常位于 Tomcat 的 conf 目录下。使用文本编辑器打开此文件。

步骤 2:添加 ErrorReportValve

<Host> 标签内添加 <Valve> 标签,并设置 classNameorg.apache.catalina.valves.ErrorReportValve,同时将 showReportshowServerInfo 设置为 false。如下所示:

xml复制

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
    <!-- 其他配置 -->
    <Valve className="org.apache.catalina.valves.ErrorReportValve" showReport="false" showServerInfo="false"/>
</Host>

步骤 3:保存并重启 Tomcat

保存 server.xml 文件后,重启 Tomcat 以使更改生效。

步骤 4:测试配置

为了验证配置是否生效,可以尝试访问一个不存在的页面或故意引发一个错误。Tomcat 应该不再显示详细的错误报告和服务器信息。

注意事项

  1. 调试问题:在开发环境中,关闭错误报告可能会使调试问题变得更加困难。因此,建议仅在生产环境中关闭错误报告。

  2. 日志记录:虽然错误报告被屏蔽了,但错误信息仍然会记录在 Tomcat 的日志文件中。确保你的日志记录策略能够满足故障排查的需求。

  3. 自定义错误页面:为了提供更好的用户体验,你可以配置自定义的错误页面,当发生错误时,引导用户到这些页面。

结论

通过在 Tomcat 中配置 ErrorReportValve,我们可以有效地屏蔽错误报告和服务器信息,从而提高系统的安全性和用户体验。然而,这也意味着我们需要更加依赖日志文件来进行故障排查,因此建立一个有效的日志记录和监控策略是非常重要的。

##tomcat-embed-core-8.5.72-sources.jar!/org/apache/catalina/valves/ErrorReportValve.java

源码

isShowReport()  展示错误堆栈

isShowServerInfo()  展示版本信息

protected void report(Request request, Response response, Throwable throwable) {

        int statusCode = response.getStatus();

        // Do nothing on a 1xx, 2xx and 3xx status
        // Do nothing if anything has been written already
        // Do nothing if the response hasn't been explicitly marked as in error
        //    and that error has not been reported.
        if (statusCode < 400 || response.getContentWritten() > 0 || !response.setErrorReported()) {
            return;
        }

        // If an error has occurred that prevents further I/O, don't waste time
        // producing an error report that will never be read
        AtomicBoolean result = new AtomicBoolean(false);
        response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
        if (!result.get()) {
            return;
        }

        String message = Escape.htmlElementContent(response.getMessage());
        if (message == null) {
            if (throwable != null) {
                String exceptionMessage = throwable.getMessage();
                if (exceptionMessage != null && exceptionMessage.length() > 0) {
                    try (Scanner scanner = new Scanner(exceptionMessage)) {
                        message = Escape.htmlElementContent(scanner.nextLine());
                    }
                }
            }
            if (message == null) {
                message = "";
            }
        }

        // Do nothing if there is no reason phrase for the specified status code and
        // no error message provided
        String reason = null;
        String description = null;
        StringManager smClient = StringManager.getManager(
                Constants.Package, request.getLocales());
        response.setLocale(smClient.getLocale());
        try {
            reason = smClient.getString("http." + statusCode + ".reason");
            description = smClient.getString("http." + statusCode + ".desc");
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
        }
        if (reason == null || description == null) {
            if (message.isEmpty()) {
                return;
            } else {
                reason = smClient.getString("errorReportValve.unknownReason");
                description = smClient.getString("errorReportValve.noDescription");
            }
        }

        StringBuilder sb = new StringBuilder();

        sb.append("<!doctype html><html lang=\"");
        sb.append(smClient.getLocale().getLanguage()).append("\">");
        sb.append("<head>");
        sb.append("<title>");
        sb.append(smClient.getString("errorReportValve.statusHeader",
                String.valueOf(statusCode), reason));
        sb.append("</title>");
        sb.append("<style type=\"text/css\">");
        sb.append(TomcatCSS.TOMCAT_CSS);
        sb.append("</style>");
        sb.append("</head><body>");
        sb.append("<h1>");
        sb.append(smClient.getString("errorReportValve.statusHeader",
                String.valueOf(statusCode), reason)).append("</h1>");
        if (isShowReport()) {
            sb.append("<hr class=\"line\" />");
            sb.append("<p><b>");
            sb.append(smClient.getString("errorReportValve.type"));
            sb.append("</b> ");
            if (throwable != null) {
                sb.append(smClient.getString("errorReportValve.exceptionReport"));
            } else {
                sb.append(smClient.getString("errorReportValve.statusReport"));
            }
            sb.append("</p>");
            if (!message.isEmpty()) {
                sb.append("<p><b>");
                sb.append(smClient.getString("errorReportValve.message"));
                sb.append("</b> ");
                sb.append(message).append("</p>");
            }
            sb.append("<p><b>");
            sb.append(smClient.getString("errorReportValve.description"));
            sb.append("</b> ");
            sb.append(description);
            sb.append("</p>");
            if (throwable != null) {
                String stackTrace = getPartialServletStackTrace(throwable);
                sb.append("<p><b>");
                sb.append(smClient.getString("errorReportValve.exception"));
                sb.append("</b></p><pre>");
                sb.append(Escape.htmlElementContent(stackTrace));
                sb.append("</pre>");

                int loops = 0;
                Throwable rootCause = throwable.getCause();
                while (rootCause != null && (loops < 10)) {
                    stackTrace = getPartialServletStackTrace(rootCause);
                    sb.append("<p><b>");
                    sb.append(smClient.getString("errorReportValve.rootCause"));
                    sb.append("</b></p><pre>");
                    sb.append(Escape.htmlElementContent(stackTrace));
                    sb.append("</pre>");
                    // In case root cause is somehow heavily nested
                    rootCause = rootCause.getCause();
                    loops++;
                }

                sb.append("<p><b>");
                sb.append(smClient.getString("errorReportValve.note"));
                sb.append("</b> ");
                sb.append(smClient.getString("errorReportValve.rootCauseInLogs"));
                sb.append("</p>");

            }
            sb.append("<hr class=\"line\" />");
        }
        if (isShowServerInfo()) {
            sb.append("<h3>").append(ServerInfo.getServerInfo()).append("</h3>");
        }
        sb.append("</body></html>");

        try {
            try {
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                if (container.getLogger().isDebugEnabled()) {
                    container.getLogger().debug("status.setContentType", t);
                }
            }
            Writer writer = response.getReporter();
            if (writer != null) {
                // If writer is null, it's an indication that the response has
                // been hard committed already, which should never happen
                writer.write(sb.toString());
                response.finishResponse();
            }
        } catch (IOException | IllegalStateException e) {
            // Ignore
        }

    }

相关文章:

  • Git分支管理:从入门到高效协作
  • 2025牛客寒假算法基础集训营1
  • 微信小程序 - 组件
  • ASP.NET Core SixLabors.ImageSharp v3.x 的图像实用程序类
  • 【开发工具】开发一个类postman的idea插件
  • Jenkins 配置 Git Parameter 四
  • 怎么使用服务器运行pySCENIC
  • 无人机信号调制技术原理
  • ESP学习-1(MicroPython VSCode开发环境搭建)
  • Java Virtual Machine(JVM)
  • Sass基础知识以及常用知识整理
  • (一)获取数据和读取数据
  • Android:播放Rtsp视频流的两种方式
  • 【工业安全】-CVE-2022-35561- Tenda W6路由器 栈溢出漏洞
  • 网络技术介绍
  • spring集成activiti流程引擎(源码)
  • 微服务SpringCloud Alibaba组件nacos教程【详解naocs基础使用、服务中心配置、集群配置,附有案例+示例代码】
  • 如何通过AI轻松制作PPT?让PPT一键生成变得简单又高效
  • 【AWS】EC2 安全组设置
  • Elasticvue使用总结
  • 宋徽宗《芙蓉锦鸡图》亮相,故宫首展历代动物绘画
  • 上汽集团一季度净利润30.2亿元,同比增长11.4%
  • 这座“蚌埠住了”的城市不仅会接流量,也在努力成为文旅实力派
  • 大学男生被捉奸后将女生推下高楼?桂林理工大学辟谣
  • 打造全域消费场景,上海大世界百个演艺娱乐新物种待孵化
  • 上海乐高乐园建设进入最后冲刺,开园限量纪念年卡将于5月开售