当 URL 路径中出现双斜杠时,如何使用 Elastic Beanstalk (Apache+Tomcat) 解决 HTTP 404 错误,例如https://uat.myserver//rest/s

Posted

技术标签:

【中文标题】当 URL 路径中出现双斜杠时,如何使用 Elastic Beanstalk (Apache+Tomcat) 解决 HTTP 404 错误,例如https://uat.myserver//rest/something【英文标题】:How to resolve HTTP 404 error with Elastic Beanstalk (Apache+Tomcat) when double-slash in URL path, e.g. https://uat.myserver//rest/something 【发布时间】:2021-06-04 16:02:22 【问题描述】:

我有一个托管在 Amazon Web Services 中的 Java Web 应用程序,它运行在带有 Amazon Linux 的退役 Tomcat 8 上。

我尝试创建一个新环境来测试在最新的 Tomcat 8.5 上运行该应用程序,并在 Amazon Linux 2 上运行 Corretto 11。

在此过程中,我遇到了一个大问题,在我的应用程序中,它使用了一个基本 URL,例如https://myserver.com 它正在做一些字符串连接来添加路径,例如/rest/myendpoint 当然应该被解析为

https://myserver.com/rest/myendpoint

但不幸的是,它在不知不觉中通过 C# 的 new URL() 传递,它在连接之前附加了一个斜杠。

所以

https://myserver.com/rest/myendpoint

被发送到服务器

https://myserver.com/rest//myendpoint

(注意rest// 应该是rest/

在将 Java war 文件部署到新环境后,来自应用程序的一些请求失败并显示 404。我分析了这些网络日志,当然是所有在路径中有双转义的 URL。

作为在 Postman 中编写请求以使单斜杠正常工作的测试,双引号失败并出现 HTTP 404,就像应用程序一样。

现在的问题是应用已经在野外使用了,我们无法更改应用,因为这将涉及很长的延迟(构建它,应用商店批准过程,然后等待每个人升级应用) ,很可能是几个月。

我在 AWS 门户中找不到任何东西来配置它。

我确实尝试过切换到 nginx,但遇到了同样的错误。

我确实看到有人提到使用 .eb-extensions,但整个 apache re-write / mod 规则对我来说非常陌生。实际上,我想将 http:// 或 https:// 之后的任何双斜杠重写为单斜杠。你能告诉我如何做到这一点吗?

我正在将 Elastic Beanstalk 与 Tomcat(目前由 Apache 支持)和最新的 Tomcat 平台版本 - Tomcat 8.5 以及在 64 位 Amazon Linux 2 上运行的 Corretto 11 一起使用。

谢谢。

【问题讨论】:

生成 URL 的是 Java 还是 C#? 嗨@OlafKock 该应用程序是c#,但不幸的是,我等不及该应用程序被修复、推出和大多数用户更新。同时,服务器端需要在 AWS .ebexensions 中进行某种 Apache 重写来执行此清理任务。 ***.com/questions/17080652/… 应该给你必要的 RewriteRules,docs.aws.amazon.com/elasticbeanstalk/latest/dg/… 有放置文件的例子。 【参考方案1】:

因为我真的不想与 .ebextensions 搞混,所以我扩展了一个现有的 servlet 过滤器(链中最早的)来检查路径。然后我就可以使用调度程序进行转发,并且效果很好。

虽然我确信我可以用 reg-ex 做一些更清洁的事情,但这对我来说已经成功了,我可以先用 Postman 在本地测试它。

package com.devology.servlet.filters;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class AuthenticationFilter implements Filter 

    public AuthenticationFilter() 
    

    private boolean doBeforeProcessing(ServletRequest request, ServletResponse response)
            throws IOException, ServletException 

        HttpServletRequest hsr = (HttpServletRequest) request;
        final String path = hsr.getServletPath();
        String fullUrl = hsr.getRequestURL().toString();

        String remoteAddress = hsr.getRemoteAddr();

        // Example URL from bad app...
        //
        // http://localhost:8084/MyApp//rest/login
        //
        // path        =                                    /rest
        // fullUrl     = http://localhost:8084/MyApp//rest/login
        // indexOfPath =                                    ^ = 34
        // 
        // If the character before the start of the path is also a slash then
        // we need to internally forward
        int indexOfPath = fullUrl.indexOf(path + "/");
        boolean needsUrlRewrite = false;
        if (indexOfPath != -1) 
            String previousCharacter = fullUrl.substring(indexOfPath - 1, indexOfPath);
            needsUrlRewrite = "/".equals(previousCharacter);
        
        if (needsUrlRewrite) 

            // Just take the path from the point of indexOfPath, .e.g /rest/login
            String rewrittenPath = fullUrl.substring(indexOfPath);
            RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher(rewrittenPath);
            dispatcher.forward(request, response);
            return false;
        

        // Any other checks like authorisation, or return true to let all through
        return true;
    

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException 

        if (doBeforeProcessing(request, response)) 
            chain.doFilter(request, response);
        
    

    @Override
    public void init(FilterConfig fc) throws ServletException 
        // Your Init
    

    @Override
    public void destroy() 
        // Your cleanup
    


这假设您已经在 web.xml 中像这样配置它...

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <filter>
        <filter-name>AuthenticationFilter</filter-name>
        <filter-class>com.devology.servlet.filters.AuthenticationFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AuthenticationFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspf</url-pattern>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>10</session-timeout>
    </session-config>
    <error-page>
        <error-code>500</error-code>
        <location>/error-500.html</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/error-404.html</location>
    </error-page>
</web-app>

我没有解决 .ebextensions 和 Apache 配置的问题,因为我真的不知道自己在做什么,而上面的 servelet 过滤器正是我需要的。

【讨论】:

以上是关于当 URL 路径中出现双斜杠时,如何使用 Elastic Beanstalk (Apache+Tomcat) 解决 HTTP 404 错误,例如https://uat.myserver//rest/s的主要内容,如果未能解决你的问题,请参考以下文章

IDEA中用jetty启动web项目时,url路径包含双斜杠会返回404

网络资源路径的双斜杠//和双反斜杠\的区别

路径名中的斜杠反斜杠双反斜杠

如何在 apache 2.4 的 url 中删除双斜杠//?

以双斜杠//开头的URL – 依赖协议的URL

url前面双斜杠单斜杠无斜杠点+单斜杠的总结