我的Web应用程序是使用Struts2开发的,直到最近才运行良好。突然其中一个模块开始出现故障。
故障模块是“更新学生详细信息”页面。这个页面有很多字段,如'schoolName','degreeName'等。
School 1: <input name="schoolName">
School 2: <input name="schoolName">
.....
School n: <input name="schoolName">
如前所述,该页面直到最近一直运行良好。现在,'schoolName','degreeName'等的一个/多个值在服务器端被接收为“”(EMPTY STRING)。
为了调试,我在eclipse中使用了firebug和远程调试。我发现后置参数在客户端是正确的。例如,在其中一份提交文件中,后参数如下(我从firebug中注意到它们)。
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--
但在服务器端,请求参数如下:
schoolName=[ABC Institute, Test School, XYZ, , XXXX School],
在这种特殊情况下,“德克萨斯研究所”被收到“”(EMPTY STRING)。这不是一贯发生的。即成为NULL(或空字符串)似乎随机给我的参数 - 一个实例中,参数schoolName [3]成为空如上所示,参数schoolName [2]另一个提交等有时中变得无效,没有一个参数无效。
以下是操作定义中的拦截器列表。
List of interceptors:
----------------------
FileUploadInterceptor
org.apache.struts2.interceptor.FileUploadInterceptor
ServletConfigInterceptor
org.apache.struts2.interceptor.ServletConfigInterceptor StaticParametersInterceptor
com.opensymphony.xwork2.interceptor.StaticParametersInterceptor
ParametersInterceptor
com.opensymphony.xwork2.interceptor.ParametersInterceptor
MyCustomInterceptor
com.xxxx.yyyy.interceptors.GetLoggedOnUserInterceptor
这个问题对我来说似乎很奇怪,而且我无法对问题的确切原因进行归零。在这方面的任何帮助将受到高度赞赏。提前致谢。
谢谢, 拉古拉姆
答案 0 :(得分: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);
}
}
}
答案 1 :(得分:0)
这个tomcat bug怎么样:https://issues.apache.org/bugzilla/show_bug.cgi?id=37794
当带有transfer-encoding的HTTP / 1.1客户端POST:chunked到servlet时, getParameter()系列和getQueryString()方法无法检索 通过什么都不返回正确的结相反,阅读直到文件结束 在servlets输入流上产生正确的结果。
修复程序在6.0.21中。