httpServletRequest中的流只能读取一次的原因
首先,我们复习一下InputStream read方法的基础知识,
java InputStream read方法内部有一个,postion,标志当前流读取到的位置,每读取一次,位置就会移动一次,如果读到最后,InputStream.read方法会返回-1,标志已经读取完了,如果想再次读取,可以调用inputstream.reset方法,position就会移动到上次调用mark的位置,mark默认是0,所以就能从头再读了。
当然,能否reset是有条件的,它取决于markSupported,markSupported() 方法返回是否可以mark/reset
我们再回头看request.getInputStream
request.getInputStream返回的值是ServletInputStream,查看ServletInputStream源码发现,没有重写reset方法,所以查看InputStream源码发现marksupported 返回false,并且reset方法,直接抛出异常。
InputStream.java
public boolean markSupported() {
return false;
}
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
综上所述,在request.getinputstream读取一次后position到了文件末尾,第二次就读取不到数据,由于无法reset(),所以,request.getinputstream只能读取一次。
总结:
这个问题最根本还是对java IO的read、reset方法的深入理解,尤其是read方法的内部实现原理。
附ServletInputStream.java源码
/*
* 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 javax.servlet; import java.io.IOException;
import java.io.InputStream; /**
* Provides an input stream for reading binary data from a client request,
* including an efficient <code>readLine</code> method for reading data one line
* at a time. With some protocols, such as HTTP POST and PUT, a
* <code>ServletInputStream</code> object can be used to read data sent from the
* client.
* <p>
* A <code>ServletInputStream</code> object is normally retrieved via the
* {@link ServletRequest#getInputStream} method.
* <p>
* This is an abstract class that a servlet container implements. Subclasses of
* this class must implement the <code>java.io.InputStream.read()</code> method.
*
* @see ServletRequest
*/
public abstract class ServletInputStream extends InputStream { /**
* Does nothing, because this is an abstract class.
*/
protected ServletInputStream() {
// NOOP
} /**
* Reads the input stream, one line at a time. Starting at an offset, reads
* bytes into an array, until it reads a certain number of bytes or reaches
* a newline character, which it reads into the array as well.
* <p>
* This method returns -1 if it reaches the end of the input stream before
* reading the maximum number of bytes.
*
* @param b
* an array of bytes into which data is read
* @param off
* an integer specifying the character at which this method
* begins reading
* @param len
* an integer specifying the maximum number of bytes to read
* @return an integer specifying the actual number of bytes read, or -1 if
* the end of the stream is reached
* @exception IOException
* if an input or output exception has occurred
*/
public int readLine(byte[] b, int off, int len) throws IOException { if (len <= 0) {
return 0;
}
int count = 0, c; while ((c = read()) != -1) {
b[off++] = (byte) c;
count++;
if (c == '\n' || count == len) {
break;
}
}
return count > 0 ? count : -1;
} /**
* Returns <code>true</code> if all the data has been read from the stream,
* else <code>false</code>.
*
* @since Servlet 3.1
*/
public abstract boolean isFinished(); /**
* Returns <code>true</code> if data can be read without blocking, else
* <code>false</code>. If this method is called and returns false, the
* container will invoke {@link ReadListener#onDataAvailable()} when data is
* available.
*
* @since Servlet 3.1
*/
public abstract boolean isReady(); /**
* Sets the {@link ReadListener} for this {@link ServletInputStream} and
* thereby switches to non-blocking IO. It is only valid to switch to
* non-blocking IO within async processing or HTTP upgrade processing.
*
* @param listener The non-blocking IO read listener
*
* @throws IllegalStateException If this method is called if neither
* async nor HTTP upgrade is in progress or
* if the {@link ReadListener} has already
* been set
* @throws NullPointerException If listener is null
*
* @since Servlet 3.1
*/
public abstract void setReadListener(ReadListener listener);
}
以上这篇浅谈request.getinputstream只能读取一次的问题就是小编分享给大家的全部内容了,希望能给大家一个参考。
httpServletRequest中的流只能读取一次的原因的更多相关文章
- springboot请求体中的流只能读取一次的问题
场景交代 在springboot中添加拦截器进行权限拦截时,需要获取请求参数进行验证.当参数在url后面时(queryString)获取参数进行验证之后程序正常运行.但是,当请求参数在请求体中的时候, ...
- 大白话讲解如何解决HttpServletRequest的请求参数只能读取一次的问题
大家在开发过程中,可能会遇到对请求参数做下处理的场景,比如读取上送的参数中看调用方上送的系统编号是否是白名单里面的(更多的会用request中获取IP地址判断).需要对请求方上送的参数进行大小写转换或 ...
- 解决SpringMVC拦截器中Request数据只能读取一次的问题
解决SpringMVC拦截器中Request数据只能读取一次的问题 开发项目中,经常会直接在request中取数据,如Json数据,也经常用到@RequestBody注解,也可以直接通过request ...
- request.getInputStream() 流只能读取一次问题
问题: 一次开发过程中同事在 sptring interceptor 中获取 request body 中值,以对数据的校验和预处理等操作 .导致之后spring 在读取request body 值做 ...
- Java中IO流文件读取、写入和复制
//构造文件File类 File f=new File(fileName); //判断是否为目录 f.isDirectory(); //获取目录下的文件名 String[] fileName=f.li ...
- 解决HttpServletRequest的输入流只能读取一次的问题
背景 通常对安全性有要求的接口都会对请求参数做一些签名验证,而我们一般会把验签的逻辑统一放到过滤器或拦截器里,这样就不用每个接口都去重复编写验签的逻辑. 在一个项目中会有很多的接口,而不同的接口可能接 ...
- spring应用中多次读取http post方法中的流(附源码)
一.问题简述 先说下为啥有这个需求,在基于spring的web应用中,一般会在controller层获取http方法body中的数据. 方式1: 比如http请求的content-type为appli ...
- 解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题
首先我们来描述一下在开发中遇到的问题,场景如下: 比如我们要拦截所有请求,获取请求中的某个参数,进行相应的逻辑处理:比如我要获取所有请求中的公共参数 token,clientVersion等等:这个时 ...
- 解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法
摘要: 大家知道, StringMVC中@RequestBody是读取的流的方式, 如果在之前有读取过流后, 发现就没有了. 我们来看一下核心代码: filter中主要做的事情, 就是来校验请求是否合 ...
随机推荐
- Algorithm 用各种语言写出n!的算法
写出n!的算法 C# 递归方式: class Program { static void Main(string[] args) { Console.WriteLine("请输入一个数!&q ...
- RabbitMQ广播模式
广播模式:1对多,produce发送一则消息多个consumer同时收到.注意:广播是实时的,produce只负责发出去,不会管对端是否收到,若发送的时刻没有对端接收,那消息就没了,因此在广播模式下设 ...
- Python 面向对象编程的一些特征 及 单例模式的实现, 父类方法的调用(python2/python3)
一.面向对象编程几个特征(封装, 继承,多态) 1.封装:类里面封装函数和变量, 在将类进行实例化成实例对象时进行传参, 从而生成不同的实例对象,增加代码的复用. 2.继承:子类可以继承父类的方法和属 ...
- Python网络通信
day26 网络通信 参考: http://www.cnblogs.com/yuanchenqi/articles/5692716.html 男生是client端,字条是socket(sk),通过sk ...
- Android之系统Action大全
String ADD_SHORTCUT_ACTION 动作:在系统中添加一个快捷方式.. “android.intent.action.ADD_SHORTCUT” String ALL_APPS_AC ...
- day 43 mysql 学习 以及pymysql 学习
前情提要: 本次主要学习sql 的难点, 多表查询以及连接python 一:多表关联 >多表查询的缺点 二:单表的连表查询[自关联查询] 三:子查询 >主查询 >主查询 >主 ...
- Python “ValueError: incomplete format” print(“a%” % ”)
解决python打印%号和%format输出问题 >>> print('%s' %'1') 1 >>> print('%s%' %'1') Traceback (m ...
- 社区发现的3个评估指标:标准化互信息NMI,ARI指标,以及模块度(modularity)
转载请注明出处:http://www.cnblogs.com/bethansy/p/6890972.html 一.已知真实社区划分结果 1.NMI指数,互信息和标准化互信息 具体公式和matlab代码 ...
- Java模拟双色球彩票
package practice1; import java.util.Random; import java.util.Scanner; public class Test3 { /** * * 模 ...
- 【字符串】Reverse Words in a String(两个栈)
题目: Given an input string, reverse the string word by word. For example,Given s = "the sky is b ...