GVKun编程网logo

一次读取后,Http Servlet请求会丢失POST正文中的参数(servletinputstream多次读取)

23

对于一次读取后,HttpServlet请求会丢失POST正文中的参数感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解servletinputstream多次读取,并且为您提供关于035.[转

对于一次读取后,Http Servlet请求会丢失POST正文中的参数感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解servletinputstream多次读取,并且为您提供关于035.[转] 获取HttpServletRequest请求Body中的内容、groovy servlet java.lang.NoSuchMethodError: javax.servlet.http.HttpServletResponse.getStatus()I、Http get请求url中的参数和post请求中的body数据存放在哪里了?后台怎么获取?getParameter()作用最本质解释。、HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向的宝贵知识。

本文目录一览:

一次读取后,Http Servlet请求会丢失POST正文中的参数(servletinputstream多次读取)

一次读取后,Http Servlet请求会丢失POST正文中的参数(servletinputstream多次读取)

我正在尝试访问Java Servlet过滤器中的两个http请求参数,这里没有新内容,但是很惊讶地发现这些参数已经被消耗了!因此,它在过滤器链中不再可用。

似乎只有在参数进入POST请求正文(例如表单提交)时才会发生这种情况。

有没有办法读取参数而不消耗它们?

答案1

小编典典

顺便说一句,解决此问题的另一种方法是不使用筛选器链,而是使用可以在已解析请求主体上运行的方面来构建自己的拦截器组件。由于您只需将请求InputStream转换为自己的模型对象一次,这样做也可能会更有效率。

但是,我仍然认为要多次读取请求正文是合理的,尤其是在请求通过过滤器链移动时。通常,我会将过滤器链用于要保留在HTTP层的某些操作,这些操作与服务组件分离。

正如Will Hartung所建议的那样,我是通过扩展HttpServletRequestWrapper,使用请求InputStream并实质上缓存字节来实现的。

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {  private ByteArrayOutputStream cachedBytes;  public MultiReadHttpServletRequest(HttpServletRequest request) {    super(request);  }  @Override  public ServletInputStream getInputStream() throws IOException {    if (cachedBytes == null)      cacheInputStream();      return new CachedServletInputStream();  }  @Override  public BufferedReader getReader() throws IOException{    return new BufferedReader(new InputStreamReader(getInputStream()));  }  private void cacheInputStream() throws IOException {    /* Cache the inputstream in order to read it multiple times. For     * convenience, I use apache.commons IOUtils     */    cachedBytes = new ByteArrayOutputStream();    IOUtils.copy(super.getInputStream(), cachedBytes);  }  /* An inputstream which reads the cached request body */  public class CachedServletInputStream extends ServletInputStream {    private ByteArrayInputStream input;    public CachedServletInputStream() {      /* create a new input stream from the cached request body */      input = new ByteArrayInputStream(cachedBytes.toByteArray());    }    @Override    public int read() throws IOException {      return input.read();    }  }}

现在,通过在过滤器链中传递原始请求之前,可以包装原始请求多次读取请求主体:

public class MyFilter implements Filter {  @Override  public void doFilter(ServletRequest request, ServletResponse response,        FilterChain chain) throws IOException, ServletException {    /* wrap the request in order to read the inputstream multiple times */    MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);    /* here I read the inputstream and do my thing with it; when I pass the     * wrapped request through the filter chain, the rest of the filters, and     * request handlers may read the cached inputstream     */    doMyThing(multiReadRequest.getInputStream());    //OR    anotherUsage(multiReadRequest.getReader());    chain.doFilter(multiReadRequest, response);  }}

该解决方案还将允许您通过这些getParameterXXX方法多次读取请求正文,因为底层调用是getInputStream(),当然,它将读取缓存的请求InputStream

编辑

对于较新版本的ServletInputStream界面。您需要提供其他一些方法的实现,例如isReadysetReadListener等等。请参考下面的注释中提供的问题。

035.[转] 获取HttpServletRequest请求Body中的内容

035.[转] 获取HttpServletRequest请求Body中的内容

注意:

HttpServletRequest 请求中的 body 内容仅能调用 request.getInputStream(), request.getReader()和request.getParameter("key") 方法读取一次,重复读取会报 java.io.IOException: Stream closed 异常。
原文:https://blog.csdn.net/pengjunlee/article/details/79416687

 

public String getBodyString(HttpServletRequest request) throws IOException {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString().trim();
    }

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
 
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
 
public class HttpServletRequestReader
{
 
    // 字符串读取
    // 方法一
    public static String ReadAsChars(HttpServletRequest request)
    {
 
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder("");
        try
        {
            br = request.getReader();
            String str;
            while ((str = br.readLine()) != null)
            {
                sb.append(str);
            }
            br.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != br)
            {
                try
                {
                    br.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
 
    // 方法二
    public static void ReadAsChars2(HttpServletRequest request)
    {
        InputStream is = null;
        try
        {
            is = request.getInputStream();
            StringBuilder sb = new StringBuilder();
            byte[] b = new byte[4096];
            for (int n; (n = is.read(b)) != -1;)
            {
                sb.append(new String(b, 0, n));
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != is)
            {
                try
                {
                    is.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
 
    }
 
    // 二进制读取
    public static byte[] readAsBytes(HttpServletRequest request)
    {
 
        int len = request.getContentLength();
        byte[] buffer = new byte[len];
        ServletInputStream in = null;
 
        try
        {
            in = request.getInputStream();
            in.read(buffer, 0, len);
            in.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (null != in)
            {
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return buffer;
    }
 
}

 

 

 

----------------------

        Enumeration enu=request.getParameterNames();  
        while(enu.hasMoreElements()){  
            String paraName=(String)enu.nextElement();  
            System.out.println(paraName+": "+request.getParameter(paraName));  
        } 

 

groovy servlet java.lang.NoSuchMethodError: javax.servlet.http.HttpServletResponse.getStatus()I

groovy servlet java.lang.NoSuchMethodError: javax.servlet.http.HttpServletResponse.getStatus()I

java.lang.NoSuchMethodError: javax.servlet.http.HttpServletResponse.getStatus()I
at org.eclipse.jetty.server.handler.ErrorHandler.handle(ErrorHandler.java:111)
at org.eclipse.jetty.server.Response.sendError(Response.java:597)
at javax.servlet.http.HttpServlet.doGet(HttpServlet.java:187)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:769)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1125)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1059)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
at org.eclipse.jetty.server.httpconnection.onFillable(httpconnection.java:248)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:610)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:539)

at java.lang.Thread.run(Thread.java:745)


问题原因: groovy libraries 中有个servlet api 那个是比较老的.而且被优先加载了.

解决方法: 将自己引用的servlet api 放在前面 

Http get请求url中的参数和post请求中的body数据存放在哪里了?后台怎么获取?getParameter()作用最本质解释。

Http get请求url中的参数和post请求中的body数据存放在哪里了?后台怎么获取?getParameter()作用最本质解释。

 

转载:https://blog.csdn.net/ZYK1746914945/article/details/85100575

 

相信很多人都和我有一样的困惑,ServletRequest中getParameter()方法到底取的是什么参数,这些参数又是怎么放进去的,本文简单的回答一下该问题:

首先话不多说,我们来看一下该方法的官方说明:

Returns the value of a request parameter as a String, or null if the parameter does not exist. Request parameters are extra information sent with the request. For HTTP servlets, parameters are contained in the query string or posted form data.

其实核心的一句话就是query string or posted form data,认真三遍这几个单词,此时大家是否已恍然大悟,也就是说getParameter()方法取的是query string 和 posted form data中的数据,那么query string 和 posted form data又是指的啥呢?query string就是get请求中url的?后面的参数,posted form data就是post请求中的body数据,哈哈哈,到现在是不是觉得很有点感觉了;大家平时都是用的ajax请求,无论是get还是post,我们的请求参数都是可以放在data里的,只不过ajax会判断请求类别,如果是get请求的话,ajax会把data里的值给拼接到url的后面。

好了,上面说了getParameter()方法取的是什么数据的问题,那么这些数据又是怎么放进去的呢?我相信每个爱思考的人都会想过这个问题,可能百思不得其解。那我来告诉大家这些参数是tomcat放进去的,是不是有点小懵逼,tomcat又是怎么放进去的呢,大家都知道tomcat是个容器,我们的http请求是会先经过tomcat进行处理的,它会分析http请求中的请求行、请求头、数据三部分然后分别将其放到对应的位置中,这样我们后台就可以根据getParameter(),getHeader()等方法进行取值了。好了,我相信很多人都不知道http的请求消息格式是什么样子的,比如我上面说的请求行、请求头、数据这三部分大家只是印象中好像有那么几个概念,但是并不知道这是http协议中所规定的,所以我建议大家好好去了解一下http协议,这样才会对系统的交互流程有着最本质的了解。

看到这,大家可能会想问tomcat具体是怎么处理的呢,哈哈哈,这个就需要去看tomcat的源码了。
---------------------
作者:西雅图的风
来源:CSDN
原文:https://blog.csdn.net/ZYK1746914945/article/details/85100575
版权声明:本文为博主原创文章,转载请附上博文链接!

HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向

HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向

上篇文章我们讲了 servlet 的基本原理,这章将讲一下剩余的部分。

HttpServletRequest 接口

  该接口是 ServletRequest 接口的子接口,封装了 HTTP 请求的相关信息,由 Servlet 容器创建其实现类对象并传入 service (ServletRequest req, ServletResponse res) 方法中。我们请求的详细信息都可以通过 HttpServletRequest 接口的实现类对象获取。这个实现类对象一般都是容器创建的,我们不需要管理。

HttpServletRequest 主要功能

获取请求参数

1)什么是请求参数?

请求参数就是浏览器向服务器提交的数据

2)浏览器向服务器如何发送数据

  a)附在 url 后面,如:http://localhost:8989/MyServlet/MyHttpServlet?userId=20

  b)通过表单提交

<form action="MyHttpServlet" method="post">
    你喜欢的足球队<br /><br />
    巴西<input type="checkbox" name="soccerTeam" value="Brazil" /> 
    德国<input type="checkbox" name="soccerTeam" value="German" />
    荷兰<input type="checkbox" name="soccerTeam" value="Holland" />
    <input type="submit" value="提交" />
</form>

3)使用 HttpServletRequest 对象获取请求参数

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  //一个name对应一个值
  String userId = request.getParameter("userId"); 
  System.out.println("userId="+userId); }

 

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //一个name对应一组值
    String[] soccerTeams = request.getParameterValues("soccerTeam");
    for(int i = 0; i < soccerTeams.length; i++){
        System.out.println("team "+i+"="+soccerTeams[i]);
    }
}

在请求域中保存数据

数据保存在请求域中,可以转发到其他 Servlet 或者 jsp 页面,这些 Servlet 或者 jsp 页面就会 从请求中再取出数据

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //将数据保存到request对象的属性域中request.setAttribute("attrName", "attrValueInRequest");
    //两个Servlet要想共享request对象中的数据,必须是转发的关系
    request.getRequestDispatcher("/ReceiveServlet").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //从request属性域中获取数据
    Object attribute = request.getAttribute("attrName"); 
    System.out.println("attrValue="+attribute);
}

HttpServletResponse 接口

HttpServletResponse ServletResponse 接口的子接口,封装了 HTTP 响应的相关信息,由

Servlet 容器创建其实现类对象并传入 service (ServletRequest req, ServletResponse res) 方法中。主要功能:

1)使用 PrintWriter 对象向浏览器输出数据

//通过PrintWriter对象向浏览器端发送响应信息
PrintWriter writer = res.getWriter();
writer.write("Servlet response"); writer.close();

2)实现请求重定向

请求转发与重定向

请求转发和重定向是 web 应用页面跳转的主要手段,应用十分广泛,所以我们一定要搞清楚他们的区别。

请求转发:

  1)第一个 Servlet 接收到了浏览器端的请求,进行了一定的处理,然后没有立即对请求进行响应,而是将请求 “交给下一个 Servlet” 继续处理,下一个 Servlet 处理完成之后对浏览器进行了响应。在服务器内部将请求 “交给” 其它组件继续处理就是请求的转发。对浏览器来说,一共只发了一次请求,服务器内部进行的 “转发” 浏览器感觉不到,同时浏览器地址栏中的地址不会变成 “下一个 Servlet” 的虚拟路径。

  2)在转发的情况下,两个 Servlet 可以共享 Request 对象中保存的数据

  3)转发的情况下,可以访问 WEB-INF 下的资源

  4)当需要将后台获取的数据传送到 JSP 上显示的时候,就可以先将数据存放到 Request 对象中,再转发到 JSP 从属性域中获取。此时由于是 “转发”,所以它们二者共享 Request 对象中的数据。

public class ForwardServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("forwardServlet  doGet");

        //请求的转发
        //1.调用HTTPServletRequest 的getRequestDispatcher()方法获取RequestDispatcher对象
        //调用getRequestDispatcher()方法时需要传入转发的地址
        String path = "testServlet";

        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/"+path);
        //2.调用调用HTTPServletRequest 的forward(request,response)进行请求的转发
        requestDispatcher.forward(request,response);
    }
}

请求重定向:

  1)第一个 Servlet 接收到了浏览器端的请求,进行了一定的处理,然后给浏览器一个特殊的响应消息,这个特殊的响应消息会通知浏览器去访问另外一个资源,这个动作是服务器和浏览器自动完成的,但是在浏览器地址栏里面能够看到地址的改变,会变成下一个资源的地址。

  2)对浏览器来说,一共发送两个请求,所以用户是能够感知到变化的。

  3)在重定向的情况下,不能共享 Request 对象中保存的数据。

public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("RedirectServlet doGet");

        //执行请求的重定向,直接调用reponse.sendRedirect(path)方法
        //path为重定向的地址
        String path = "testServlet";
        response.sendRedirect(path);
    }
}

转发与重定向的区别:

 

转发

重定向

浏览器地址栏

不会变化

会变化

Request

同一个请求

两次请求

API

Request 对象

Response 对象

位置

服务器内部完成

浏览器完成

WEB-INF

可以访问

不能访问

共享请求域数据

可以共享

不可以共享

目标资源

必须是当前 Web 应用中的资源

不局限于当前 Web 应用

 


图解转发和重定向

 

原文出处:https://www.cnblogs.com/java-chen-hao/p/10729903.html

我们今天的关于一次读取后,Http Servlet请求会丢失POST正文中的参数servletinputstream多次读取的分享已经告一段落,感谢您的关注,如果您想了解更多关于035.[转] 获取HttpServletRequest请求Body中的内容、groovy servlet java.lang.NoSuchMethodError: javax.servlet.http.HttpServletResponse.getStatus()I、Http get请求url中的参数和post请求中的body数据存放在哪里了?后台怎么获取?getParameter()作用最本质解释。、HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向的相关信息,请在本站查询。

本文标签: