java 枚举空指针异常?

toiithl6  于 2023-02-28  发布在  Java
关注(0)|答案(3)|浏览(255)

嗨,我正在使用HttpServletRequest,并尝试设置头集合。
下面是代码:

public static Map<String, String> getHeaders(HttpServletRequest request) { 
   Map<String, String> headers = new HashMap<String, String>();

  Enumeration<String> headerNames = request.getHeaderNames(); 
  if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                String header = request.getHeader(headerName);
                headers.put(headerName, header);
            }
        }
        return headers;

}

此方法似乎在headernames. nextElement()处抛出了Null指针异常。
是否有可能hasMoreElements检查返回true,但元素headerNames. nextElement反过来导致空指针异常?
堆栈跟踪:

Stack trace : Caused by: java.lang.NullPointerException at org.apache.tomcat.util.buf.ByteChunk.equalsIgnoreCase(ByteChunk.java:608) at 
org.apache.tomcat.util.buf.MessageBytes.equalsIgnoreCase(MessageBytes.java:325) 
at org.apache.tomcat.util.http.NamesEnumerator.findNext(MimeHeaders.java:414) at org.apache.tomcat.util.http.NamesEnumerator.nextElement(MimeHeaders.java:438) 
at org.apache.tomcat.util.http.NamesEnumerator.nextElement(MimeHeaders.java:396) at generateRequestHeaderMap...

如果你们能帮我解决这个问题就太好了。

vql8enpb

vql8enpb1#

我怀疑这个问题是由一个损坏的请求引起的。下面是findNext()正在做的事情(在Tomcat 6.0.18中):

private void  findNext() {
    next=null;
    for(  ; pos< size; pos++ ) {
        next=headers.getName( pos ).toString();
        for( int j=0; j<pos ; j++ ) {
            if( headers.getName( j ).equalsIgnoreCase( next )) {
                // duplicate.
                next=null;
                break;
            }
        }
        if( next!=null ) {
            // it's not a duplicate
            break;
        }
    }
    // next time findNext is called it will try the
    // next element
    pos++;
}

其中的要点如下:

next=headers.getName( pos ).toString();

if( headers.getName( j ).equalsIgnoreCase( next )) {

如果头文件被损坏,那么getName(j)可能返回null。如果发生这种情况,那么equalsIgnoreCase方法的ByteChunk路径将抛出NPE。
如果你要科学地追踪它,你需要:

  • 获取请求的实际原始字节,并进行取证检查,以确定损坏的性质(如果有)
  • 设置一个测试工具以允许您在附加调试器的情况下根据此请求运行应用....并在源代码处捕获异常。

非科学的方法是将Tomcat升级到Tomcat 6的最新补丁版本......或更高版本。它可能会修复问题。也可能不会。
下面是2010年Tomcat 6.0.20中关于此问题的另一个报告:

9w11ddsr

9w11ddsr2#

这就是我如何基于Apache Tomcat 6.0.20源代码在JBoss 6.1.0最终版(位于deploy/jbossweb.sar/jbossweb.jar)中成功地修补Apache Tomcat的方法:
文件名枚举器.findNext()

private void findNext() {
        next=null;
        for(  ; pos< size; pos++ ) {
            // (4 lines changed): check mb for null as suggested here: https://stackoverflow.com/questions/37493552/enumeration-null-pointer-exception/37493888#37493888
            MessageBytes mb = headers.getName( pos );
            if (mb != null) {
                next=mb.toString();
            }
            for( int j=0; j<pos ; j++ ) {
                // (2 lines changed): check mb and nex for null as suggested here: https://stackoverflow.com/questions/37493552/enumeration-null-pointer-exception/37493888#37493888
                mb = headers.getName( j );
                if(mb != null && next != null && mb.equalsIgnoreCase( next )) {
                    // duplicate.
                    next=null;
                    break;
                }
            }
            // new (just 1 comment line): if mb == null we assume next == null, thus it will be a duplicate (i.e. not found, causing no break)
            if( next!=null ) {
                // it's not a duplicate
                break;
            }
        }
        // next time findNext is called it will try the
        // next element
        pos++;
    }

当然,它没有避免https://mail-archives.apache.org/mod_mbox/tomcat-users/201002.mbox/%3c27699460.post@talk.nabble.com%3e中提到的非线程安全实现,但至少避免了在阅读不必要的标头期间出现NullPointerException。

cyvaqqii

cyvaqqii3#

我知道这很难看,但我就是这么做的:

public HashMap<String, String> fetchAllHeadersAsHashMap(HttpServletResponse httpServletResponse) {
    HashMap<String, String> headers = new HashMap<>();
    Collection<String> headerNames = null;

    int retries = 0;
    int maxRetries = 5;
    
    //this is a bug in tomcat, which doesn't return the headers in case someone else is removing or adding a header
    while (headerNames == null) {
        if (retries >= maxRetries) {
            break;
        }
        try {
            if (retries > 0) {
                Thread.sleep(100);
            }
            headerNames = new ArrayList<>(httpServletResponse.getHeaderNames());
        } catch (Throwable th) {
        }
        retries = retries + 1;
    }

    if (org.apache.commons.collections4.CollectionUtils.isEmpty(headerNames)) {
        return headers;
    }

    for (String headerName : headerNames) {
        Object value = null;
        try {
            value = httpServletResponse.getHeader(headerName);
        } catch (Throwable th) {

        }
        if (value == null) {
            continue;
        }

        headers.put(headerName, httpServletResponse.getHeader(headerName));
    }
    return headers;
}

相关问题