众所周知,request
对象中的inputStream
只能读取一次,下次再读就没有了,在一些场景中,这种特性是不适用的:比如需要在拦截器中读取请求体,然后做相关的参数校验,做完校验后请求打到Controller
中就读取不到了。
解决的方法很简单,通过HttpServletRequestWrapper
将HttpServletRequest
对象包装一下,保存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
|
/** 包装HttpServletRequest,使其inputStream可复用。**/
@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
中的副本。
评论