如何依次调用Servlet和Filter

Posted

技术标签:

【中文标题】如何依次调用Servlet和Filter【英文标题】:How to Invoke Servlet and Filter in sequence 【发布时间】:2014-10-01 11:38:54 【问题描述】:

您好,我正在开发一个 Web 应用程序,但在调用 web.xml 中提到的 serverlet 时遇到了问题。

这是我的 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">

     <servlet>
            <servlet-name>FileServlet</servlet-name>
            <servlet-class>com.tpg.fileserver.FileServlet</servlet-class>
     </servlet>
    <servlet-mapping>
            <servlet-name>FileServlet</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    <filter>
            <filter-name>AuthorizationFilter</filter-name>
            <filter-class>com.tpg.fileserver.AuthorizationFilter</filter-class>
      </filter>
      <filter-mapping>
            <filter-name>AuthorizationFilter</filter-name>
            <url-pattern>/*</url-pattern>
      </filter-mapping>

  </web-app>

问题是,当我尝试运行我的应用程序时,我希望首先运行授权过滤器,然后运行 ​​File Servelet。现在发生的事情与我想要的相反。我也尝试将 0 用于 File Servelet,但这没有帮助。下面提到的是我的过滤器类代码。

public class AuthorizationFilter implements Filter  

    private static final String kNotAuthorizedUrl = "/NotAuthorized.html";
    private static final String kTrustedHostsFileName = "trusted_hosts.txt";
    private static final String kPublicFilesFileName = "public_files.txt";

    private static final String TRUSTED_HOSTS = "TRUSTED_HOSTS";
    private static final String PUBLIC_FILES = "PUBLIC_FILES";
    private static Properties itsProperties = null;
    public static final String kPropertySingleSignOnURL = "sso-url";
    private static final String kPropertiesFileName = "metadata.properties";
    private static boolean itsInitialized = false;

    private static synchronized void initialize() 
        if (!itsInitialized) 
            try 
                ProductMetadataAPI.setProduct(Version.kProductName, Version.kPhysical);
                System.out.println("Inside Initialize");
                PersistenceAPI.isDebugging = true;
                JNDIConnectionFactory connFactory = new JNDIConnectionFactory("DataSource"); // IDB

                SingleSignOnAuthenticator.setAuthenticationUrl(ConfigurationUtils.getProperties().getProperty(kPropertySingleSignOnURL));

                SecurityAPI.setSecurity(
                    SecurityAPI.makeSecurity(
                        new StandardFactory(),
                        new PersistenceRepository(connFactory),
                        new CommonsBase64Codec(),
                        new SingleSignOnAuthenticator()));

                itsInitialized = true;
             catch (Throwable e) 
                LoggerClass.logErr(e);
            
        
    

    private void requestAuthentication(HttpServletResponse response) 
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.addHeader("WWW-Authenticate", "BASIC Realm=\"Single Sign-on\"");
        LoggerClass.logInfoMsg("SSO not set. redirecting to siteminder......");
    


    public void doFilter(ServletRequest inRequest, ServletResponse inResponse, FilterChain chain) throws IOException, ServletException 
        try 
            HttpServletRequest request = (HttpServletRequest) inRequest;
            HttpServletResponse response = (HttpServletResponse) inResponse;
            System.out.println("Before Setting Serervlet Context");
            ConfigurationUtils.setCurrentServletContext(request.getSession().getServletContext());
            System.out.println("After Setting Serervlet Context");
            initialize();

            if (request instanceof HttpServletRequest && (request.getMethod().equals("GET") || request.getMethod().equals("POST"))) 
                String remoteHost = "", authorization = "", userName = "", password = "";
                HttpServletRequest r = (HttpServletRequest)request;
                Enumeration<String> e = r.getHeaderNames();
                while (e.hasMoreElements()) 
                    String headerName = e.nextElement();
                    LoggerClass.logInfoMsg(headerName + "=" + r.getHeader(headerName));
                
                LoggerClass.logDebugMsg("Proxy-Client-IP is :" + r.getHeader("Proxy-Client-IP"));
                LoggerClass.logDebugMsg("Remote-Address-IP is :" + r.getRemoteAddr());


                remoteHost = r.getHeader("Proxy-Client-IP");
                if (remoteHost == null) 
                    remoteHost = r.getRemoteAddr();
                    LoggerClass.logDebugMsg("Remote-Address-IP ["+remoteHost + "] is requesting " + r.getRequestURI());
                else
                    LoggerClass.logDebugMsg("Proxy-Client-IP ["+remoteHost + "] is requesting " + r.getRequestURI());
                

                authorization = r.getHeader("Authorization");
                if (authorization != null) 
                    final int index = authorization.indexOf(' ');
                    if (index > 0) 
                        final String[] credentials = StringUtils.split(new String(Base64.decodeBase64(authorization.substring(index))), ':');

                        if (credentials.length == 2) 
                            userName = credentials[0].toUpperCase();
                            password = credentials[1];
                        
                    
                

                if (isSiteminderAuthenticationPresent(r)) 
                    LoggerClass.logInfoMsg("Inside Siteminder Logic ......");
                    chain.doFilter(request, response);
                    return;
                 else if (isPublic(request) || isTrusted(remoteHost)) 
                    LoggerClass.logInfoMsg("Inside Public/Trusted Host Logic ......");
                    chain.doFilter(request, response);
                    return;
                 else if (!isBasicAuthenticationPresent(userName, password)) 
                    LoggerClass.logInfoMsg("Failed in Basic Authentication Present.....");
                    requestAuthentication(response);
                 else if (!isBasicAuthenticationValid(r.getSession(), userName, password)) 
                    LoggerClass.logInfoMsg("Failed in Basic Authentication Validation.....");
                    requestAuthentication(response);
                 else 
                    chain.doFilter(request, response);
                
            
            response.sendRedirect(request.getContextPath() + kNotAuthorizedUrl);
         catch (Exception e) 
            LoggerClass.logErr(e);
            throw new RuntimeException(e);
        
    

下面提到的是我的 Servlet 部分代码:

public class FileServlet extends HttpServlet

public FileServlet()
    
         System.out.println("In fileServlet");
         this.itsRootDir = Common.getRequiredProperty(Common.kPropertyRootDir);
            // some business logic
    
@Override public void doGet(HttpServletRequest inRequest, HttpServletResponse inResponse)
    throws ServletException, IOException
    
        String theRelFileName = Common.extractFileName(inRequest, false);
        String theFileName = this.itsRootDir + theRelFileName;
        File theFile = new File(theFileName);
     //Some more Business Logic

           

下面是我在应用程序日志中获得的 Sysout 日志。在这里,我注意到一件奇怪的事情。首先调用将转到 File Servlet,然后是 Authorization Filter,然后再转到 File Servlet。

[8/8/14 0:54:05:109 EDT] 0000002b SystemOut     O In fileServlet
[8/8/14 0:54:05:161 EDT] 0000002b SystemOut     O In Authoriazation Filter
[8/8/14 0:54:05:232 EDT] 0000002b SystemOut     O In fileServlet

【问题讨论】:

AuthorizationFilter 有什么作用?向我们展示。 过滤器包装 Servlet。它们可用于 Servlet 调用前和后调用 - 您能否发布您的过滤器代码,因为我怀疑这可能是您的问题所在。有关示例,请参阅此相关帖子:***.com/questions/1323009/… @SotiriosDelimanolis:授权文件过滤器正在接受请求并对用户进行身份验证。那是我想要进入我的应用程序的第一步。它还设置了我在 File Servlet 中需要的 servlet 上下文。因此我需要在 AuthorizationFilter 之后调用 File Servlet。 @Romski:这正是我想要的。我在 AuthorizationFilter 类中有一个 do Filter 方法,但不知何故 FileServlet 首先调用。 该日志在构造函数中。它会被调用一次。它不是请求-响应周期的一部分。 【参考方案1】:

filters 始终在webapp's 启动期间按照web.xml 中定义的顺序进行初始化。

默认情况下,servlets 仅在其url-pattern 的第一个 HTTP 请求期间初始化。

所以在这种情况下,首先将解析 webapp 的 web.xml,并在 web.xml 中找到的每个 Filter 将被创建一次并保存在 server's memory

现在,当请求来自像 /* 这样的 url 模式时,容器会查找该模式并找到 servlet 的映射,因此会初始化 servlet。然后调用filter 来处理请求。

要解决这个问题,您可以更改 servlet 的 url 模式。当用户输入一些 url 模式(如 /* 重定向到过滤器类,如果他成功验证则重定向到使用其他一些 url pattern 指定的 servlet 或重定向到error page

【讨论】:

嗨.. 现在我正在尝试在 Websphere 服务器上部署这个应用程序。它在 Weblogic Server 上使用相同的配置正常工作,但在 Websphere 应用程序上却出现问题。所以我的问题是,对于不同的应用程序服务器,这种行为会有所不同吗?【参考方案2】:

上述问题的答案是 FileServlet 中的构造函数在过滤器执行之前被调用。为了解决这个问题,我将构造函数更改为在 Servlet 的 doget() 方法中调用的公共方法。在此更改之后,过滤器首先被调用,然后是 servlet 被调用。

【讨论】:

以上是关于如何依次调用Servlet和Filter的主要内容,如果未能解决你的问题,请参考以下文章

Java Servlet 过滤器和其他对象和实体管理器的范围

servlet中为啥doget要调用dopost?默认调用哪个?默认都调用?

如何在 Servlet 中调用 java Rest WebService

你如何从android客户端调用远程servlet?

java web servlet 调用 dao层方法 总出错 !!!!新手求解,多谢!!!

如何在不使用表单的情况下从 jsp 调用 servlet