解决HttpServletRequest.inputStream复用问题

众所周知,request对象中的inputStream只能读取一次,下次再读就没有了,在一些场景中,这种特性是不适用的:比如需要在拦截器中读取请求体,然后做相关的参数校验,做完校验后请求打到Controller中就读取不到了。

解决的方法很简单,通过HttpServletRequestWrapperHttpServletRequest对象包装一下,保存requestBody的副本,最后通过过滤器将包装后的request对象替换掉。

附完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* 包装HttpServletRequest,使其inputStream可复用。
* @author wuwenze
* @date 2019-06-21
*/
@Configuration
@Order(1)
@WebFilter(urlPatterns = ["/**"])
class HttpServletRequestWrapperFilter : Filter {
override fun doFilter(req: ServletRequest?, resp: ServletResponse?, chain: FilterChain?) {
when (req) {
is HttpServletRequest -> chain?.doFilter(MyHttpServletRequestWrapper(req), resp)
else -> chain?.doFilter(req, resp)
}
}

class MyHttpServletRequestWrapper(request: HttpServletRequest) : HttpServletRequestWrapper(request) {
private var body: ByteArray = request.getBodyString().toByteArray(Charset.forName("UTF-8"))

@Throws(IOException::class)
override fun getReader(): BufferedReader {
return BufferedReader(InputStreamReader(inputStream))
}

@Throws(IOException::class)
override fun getInputStream(): ServletInputStream {
val byteArrayInputStream = ByteArrayInputStream(body)
return object : ServletInputStream() {

@Throws(IOException::class)
override fun read(): Int {
return byteArrayInputStream.read()
}

override fun isFinished(): Boolean {
return false
}

override fun isReady(): Boolean {
return false
}

override fun setReadListener(readListener: ReadListener) {

}
}
}
}
}

获取requestBody的扩展函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun HttpServletRequest.getBodyString(): String {
val result = StringBuffer()
var reader: BufferedReader? = null
try {
var line: String? = null
reader = BufferedReader(InputStreamReader(this.inputStream, Charset.forName("UTF-8")))
while ({ line = reader.readLine();line }() != null) {
result.append(line)
}
} catch (e: IOException) {
// ignore
} finally {
reader?.close()
}
return result.toString()
}

这样就能多次使用了,每次读取的其实是存储在MyHttpServletRequestWrapper中的副本。

# Java

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×