2009-12-27 1 views
1

내 웹 응용 프로그램은 Struts2로 개발되었으며 최근까지 제대로 작동했습니다. 모듈 중 갑자기 하나가 오작동하기 시작했습니다.게시 매개 변수가 null이됩니다 (무작위로)

오작동 모듈은 '학생 세부 정보 업데이트'페이지입니다. 이 페이지에는 'schoolName', 'degreeName'등의 입력란이 많이 있습니다. 앞서 언급 한 바와 같이

School 1: <input name="schoolName"> 

School 2: <input name="schoolName"> 

..... 
School n: <input name="schoolName"> 

이 페이지는 최근까지 완벽하게 잘 작동했다. 이제 'schoolName', 'degreeName'등의 값 중 하나 또는 여러 개가 서버 측에서 ""(비어있는 문자열)로 수신되고 있습니다.

디버깅을 위해 firebug와 원격 디버깅을 Eclipse에서 사용했습니다. 포스트 매개 변수가 클라이언트 측에서 정확하다는 것을 알았습니다. 예를 들어, 제출 중 하나 동안 사후 매개 변수는 다음과 같았습니다 (방화 녀석에게서 지적한 것).

Content-Type: multipart/form-data; boundary=---------------------------2921238217421 
Content-Length: 48893 

<OTHER_PARAMETERS> <!--Truncated for clarity --> 

-----------------------------2921238217421 
Content-Disposition: form-data; name="schoolName" 

ABC Institute 
-----------------------------2921238217421 
Content-Disposition: form-data; name="schoolName" 

Test School 
-----------------------------2921238217421 
Content-Disposition: form-data; name="schoolName" 

XYZ 
-----------------------------2921238217421 
Content-Disposition: form-data; name="schoolName" 

Texas Institute 
-----------------------------2921238217421 
Content-Disposition: form-data; name="schoolName" 

XXXX School 

-----------------------------2921238217421-- 

그러나 서버 측

는 요청 PARAMS은 다음과 같다

schoolName=[ABC Institute, Test School, XYZ, , XXXX School], 

"텍사스 연구원은"이 특정 경우에서 ""(EMPTY STRING)로서 수신한다. 이것은 일관되게 일어나지 않습니다. NULL (또는 비어있는 문자열)이되는 매개 변수는 나에게 무작위로 보입니다. 하나의 인스턴스에서 매개 변수 schoolName [3]이 위에서 설명한대로 null이되고 매개 변수 schoolName [2]가 또 다른 제출 중에 null이되는 경우가 있습니다. 매개 변수가 무효화됩니다.

다음은 작업 정의의 인터셉터 목록입니다.

이 문제는 다소 이상하게 보입니다. 문제의 정확한 원인에 대해 제로 인 할 수 없었습니다. 이와 관련하여 도움이된다면 크게 감사하겠습니다. 미리 감사드립니다.

감사합니다, 라구 람

+1

먼저 Wireshark를 사용하여 서버에서 트래픽을 캡처하여 어댑터의 모든 데이터를 수신하는지 확인하여 네트워크 전송 문제를 제거하는 것이 좋습니다.데이터가 정상적으로 보인다면 Struts2 소스를로드하고 인터셉터로 디버그하여 상황을 확인해야 할 것입니다. 질문 : 정말이'XXXX School' 후 여분의 빈 줄인가? –

+0

>>> 질문 : XXXX 학교 다음에 여분의 빈 행이 실제로 있습니까? 죄송합니다. 여분의 빈 줄은 없습니다. –

답변

1

업데이트.

양식이 다중 요청을 전송합니다 (파일 업로드가 양식에서 사용 가능하므로 필요합니다). 나는 서버에 오는 사후 데이터를 기록하기로 결정했다. 멀티 파트 포스트 데이터를 기록하도록 RequestDumperFilter.java를 수정했습니다. 이 필터를 추가 한 후에는 매개 변수 손실 문제가 중단 된 것 같습니다 (150 개의 양식 제출 중 0 개의 손실). 필터를 제거하고 문제를 다시 재현 할 수있었습니다.

감사합니다, 라구 람

/* 
* Licensed to the Apache Software Foundation (ASF) under one or more 
* contributor license agreements. See the NOTICE file distributed with 
* this work for additional information regarding copyright ownership. 
* The ASF licenses this file to You under the Apache License, Version 2.0 
* (the "License"); you may not use this file except in compliance with 
* the License. You may obtain a copy of the License at 
* 
*  http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/ 


package filters; 


import java.io.BufferedReader; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.io.StringWriter; 
import java.sql.Timestamp; 
import java.util.Enumeration; 
import java.util.Locale; 

import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletInputStream; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.Cookie; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 
import javax.xml.ws.RequestWrapper; 

import com.oreilly.servlet.multipart.BufferedServletInputStream; 



/** 
* Example filter that dumps interesting state information about a request 
* to the associated servlet context log file, before allowing the servlet 
* to process the request in the usual way. This can be installed as needed 
* to assist in debugging problems. 
* 
* @author Craig McClanahan 
* @version $Revision: 500674 $ $Date: 2007-01-28 00:15:00 +0100 (dim., 28 janv. 2007) $ 
*/ 

public final class RequestDumperFilter implements Filter { 


    // ----------------------------------------------------- Instance Variables 


    /** 
    * The filter configuration object we are associated with. If this value 
    * is null, this filter instance is not currently configured. 
    */ 
    private FilterConfig filterConfig = null; 

    // --------------------------------------------------------- Public Methods 


    /** 
    * Take this filter out of service. 
    */ 
    public void destroy() { 

     this.filterConfig = null; 

    } 


    /** 
    * Time the processing that is performed by all subsequent filters in the 
    * current filter stack, including the ultimately invoked servlet. 
    * 
    * @param request The servlet request we are processing 
    * @param result The servlet response we are creating 
    * @param chain The filter chain we are processing 
    * 
    * @exception IOException if an input/output error occurs 
    * @exception ServletException if a servlet error occurs 
    */ 
    public void doFilter(ServletRequest request, ServletResponse response, 
         FilterChain chain) 
    throws IOException, ServletException { 

     if (filterConfig == null) 
     return; 

    // Render the generic servlet request properties 
    StringWriter sw = new StringWriter(); 
    PrintWriter writer = new PrintWriter(sw); 
    writer.println("Request Received at " + 
       (new Timestamp(System.currentTimeMillis()))); 
    writer.println(" characterEncoding=" + request.getCharacterEncoding()); 
    writer.println("  contentLength=" + request.getContentLength()); 
    writer.println("  contentType=" + request.getContentType()); 
    writer.println("   locale=" + request.getLocale()); 
    writer.print("   locales="); 
    Enumeration locales = request.getLocales(); 
    boolean first = true; 
    while (locales.hasMoreElements()) { 
     Locale locale = (Locale) locales.nextElement(); 
     if (first) 
      first = false; 
     else 
      writer.print(", "); 
     writer.print(locale.toString()); 
    } 
    writer.println(); 
    Enumeration names = request.getParameterNames(); 
    while (names.hasMoreElements()) { 
     String name = (String) names.nextElement(); 
     writer.print("   parameter=" + name + "="); 
     String values[] = request.getParameterValues(name); 
     for (int i = 0; i < values.length; i++) { 
      if (i > 0) 
      writer.print(", "); 
     writer.print(values[i]); 
     } 
     writer.println(); 
    } 
    writer.println("   protocol=" + request.getProtocol()); 
    writer.println("  remoteAddr=" + request.getRemoteAddr()); 
    writer.println("  remoteHost=" + request.getRemoteHost()); 
    writer.println("   scheme=" + request.getScheme()); 
    writer.println("  serverName=" + request.getServerName()); 
    writer.println("  serverPort=" + request.getServerPort()); 
    writer.println("   isSecure=" + request.isSecure()); 

    // Render the HTTP servlet request properties 
    if (request instanceof HttpServletRequest) { 
     writer.println("---------------------------------------------"); 
     HttpServletRequest hrequest = (HttpServletRequest) request; 
     writer.println("  contextPath=" + hrequest.getContextPath()); 
     Cookie cookies[] = hrequest.getCookies(); 
      if (cookies == null) 
       cookies = new Cookie[0]; 
     for (int i = 0; i < cookies.length; i++) { 
      writer.println("   cookie=" + cookies[i].getName() + 
        "=" + cookies[i].getValue()); 
     } 
     names = hrequest.getHeaderNames(); 
     while (names.hasMoreElements()) { 
      String name = (String) names.nextElement(); 
     String value = hrequest.getHeader(name); 
      writer.println("   header=" + name + "=" + value); 
     } 
     writer.println("   method=" + hrequest.getMethod()); 
     writer.println("   pathInfo=" + hrequest.getPathInfo()); 
     writer.println("  queryString=" + hrequest.getQueryString()); 
     writer.println("  remoteUser=" + hrequest.getRemoteUser()); 
     writer.println("requestedSessionId=" + 
       hrequest.getRequestedSessionId()); 
     writer.println("  requestURI=" + hrequest.getRequestURI()); 
     writer.println("  servletPath=" + hrequest.getServletPath()); 


     /* 
     The following section is added by me to print the post data of a multipart request. 
     */ 
     writer.println("============================================="); 
     writer.println("POST-DATA:"); 
     writer.println("----------"); 
     String line; 
     BufferedRequestWrapper bufferedRequest= new BufferedRequestWrapper(hrequest); 
     //Here obtain InputStream to process POST data! 
     InputStream is = bufferedRequest.getInputStream(); 
     BufferedReader br = new BufferedReader(new InputStreamReader(is)); 
     while((line = br.readLine()) != null){ 
       writer.println(line); 
     } 
     writer.println("============================================="); 
     // Log the resulting string 
     writer.flush(); 
     filterConfig.getServletContext().log(sw.getBuffer().toString()); 
     // Pass control on to the next filter 
     chain.doFilter(bufferedRequest, response); 

    } 
    else 
    { 
     writer.println("============================================="); 

     // Log the resulting string 
     writer.flush(); 
     filterConfig.getServletContext().log(sw.getBuffer().toString()); 

     // Pass control on to the next filter 
      chain.doFilter(request, response); 
    } 
    } 


    /** 
    * Place this filter into service. 
    * 
    * @param filterConfig The filter configuration object 
    */ 
    public void init(FilterConfig filterConfig) throws ServletException { 

    this.filterConfig = filterConfig; 

    } 


    /** 
    * Return a String representation of this object. 
    */ 
    public String toString() { 

    if (filterConfig == null) 
     return ("RequestDumperFilter()"); 
    StringBuffer sb = new StringBuffer("RequestDumperFilter("); 
    sb.append(filterConfig); 
    sb.append(")"); 
    return (sb.toString()); 

    } 

    public class BufferedRequestWrapper extends HttpServletRequestWrapper { 

     ByteArrayInputStream bais; 
     ByteArrayOutputStream baos; 
     BufferedServletInputStream bsis; 
     byte [] buffer; 

     public BufferedRequestWrapper(HttpServletRequest req) throws IOException { 
     super(req); 
     // Read InputStream and store its content in a buffer. 
     InputStream is = req.getInputStream(); 
     baos = new ByteArrayOutputStream(); 
     byte buf[] = new byte[1024]; 
     int letti; 
     while ((letti=is.read(buf))>0) baos.write(buf,0,letti); 
     buffer = baos.toByteArray(); 
     } 

     public ServletInputStream getInputStream() { 
     try { 
     // Generate a new InputStream by stored buffer 
     bais = new ByteArrayInputStream(buffer); 
     // Istantiate a subclass of ServletInputStream 
     // (Only ServletInputStream or subclasses of it are accepted by the servlet engine!) 
     bsis = new BufferedServletInputStream(bais); 
     } 
     catch (Exception ex) { 
     ex.printStackTrace(); 
     } 
     finally { 
     return bsis; 
     } 
     } 

     } 

    /* 
    Subclass of ServletInputStream needed by the servlet engine. 
    All inputStream methods are wrapped and are delegated to 
    the ByteArrayInputStream (obtained as constructor parameter)! 
    */ 
    public class BufferedServletInputStream extends ServletInputStream { 

    ByteArrayInputStream bais; 

    public BufferedServletInputStream(ByteArrayInputStream bais) { 
    this.bais = bais; 
    } 

    public int available() { 
    return bais.available(); 
    } 

    public int read() { 
    return bais.read(); 
    } 

    public int read(byte[] buf,int off,int len) { 
    return bais.read(buf,off,len); 
    } 

    } 


} 
0

무엇이 바람둥이의 버그에 대한 :는 HTTP/전송 인코딩 1.1 클라이언트 POST가 https://issues.apache.org/bugzilla/show_bug.cgi?id=37794

: 서블릿에 청크, 의 getParameter() 가족과 getQueryString() 메서드는 아무 것도 반환하지 않고 올바른 결과를 검색하지 못합니다. 반대로 서블릿 입력 스트림에서 파일 끝 ( )까지 읽을 때 올바른 결과가 생성됩니다.

수정 사항은 6.0.21에 있습니다.