2019独角兽企业重金招聘Python工程师标准>>>
Filter中读取输入流
在很多场景中,我们需要读取接口调用方的原始报文,以方便出现问题的时候进行对质、修复,但是在spring mvc中的输入流只允许读取一次,在Filter中读取之后action中就无法就行绑定了,如下面的代码
if(request != null){
//读取原始报文
val originText = request.inputStream.bufferedReader().readText()
println(originText)
chain?.doFilter(request,response)
}
这样在模型绑定的时候直接抛出
Required request body is missing
按照常理上思维,输入流读取到最后,我重置不就行了吗,事实上尝试之后发现不可行,spring mvc根本没有实现,那我们只能自己造轮子了
class ResettableStreamHttpServletRequest(val request: HttpServletRequest) : HttpServletRequestWrapper(request) {
//把输入流缓存到字节数组
private val rawData: ByteArray = IOUtils.toByteArray(this.request.inputStream)
//可重置的输入流对象
private val servletStream: ResettableServletInputStream
init {
//初始化的时候就把缓存的字节数组读到流中
servletStream = ResettableServletInputStream(ByteArrayInputStream(rawData))
}
internal fun resetInputStream() {
//重置的时候,重新构造一个输入流对象
servletStream.stream = ByteArrayInputStream(rawData)
}
override fun getInputStream(): ServletInputStream {
return servletStream
}
override fun getReader(): BufferedReader {
val encoding = characterEncoding
return if (encoding != null) {
BufferedReader(InputStreamReader(servletStream, encoding))
} else {
BufferedReader(InputStreamReader(servletStream))
}
}
}
//必须定义一个ServletInputStream,它没有提供公开的构造方法
class ResettableServletInputStream(var stream: InputStream) : ServletInputStream() {
override fun isReady(): Boolean {
return true
}
override fun isFinished(): Boolean {
return false
}
override fun setReadListener(listener: ReadListener?) {
}
override fun read(): Int {
return stream.read()
}
}
在Filter中使用ResettableStreamHttpServletRequest
val resettableStreamHttpServletRequest = ResettableStreamHttpServletRequest(request = request as HttpServletRequest)
//读取原始报文
val orginText = resettableStreamHttpServletRequest.inputStream.bufferedReader().readText()
println(orginText)
resettableStreamHttpServletRequest.resetInputStream()
chain?.doFilter(resettableStreamHttpServletRequest,response)