我有完全相同的問題要解決。我使用了Handler
的特徵,就像它在GZipSupport.scala中完成的一樣,並且使用這個answer作爲參考實現。
我建了一個ServletOutputStreamCopier
其持有的每一個字節的原始OutputStream
的副本,這兩個流:
class ServletOutputStreamCopier(orig: ServletOutputStream) extends ServletOutputStream {
val copy: ByteArrayOutputStream = new ByteArrayOutputStream(1024)
override def write(b: Int): Unit = {
orig.write(b)
copy.write(b)
}
override def setWriteListener(writeListener: WriteListener): Unit = orig.setWriteListener(writeListener)
override def isReady: Boolean = orig.isReady
def getCopy: Array[Byte] = copy.toByteArray
}
然後,ResponseCopier
,這是一個HttpServletResponseWrapper
與先前定義的ServletOutputStreamCopier
和暴露copy
到外:
class ResponseCopier(res: HttpServletResponse, sos: ServletOutputStreamCopier, w: PrintWriter) extends HttpServletResponseWrapper(res) {
override def getOutputStream: ServletOutputStream = new ServletOutputStreamCopier(sos)
override def getWriter: PrintWriter = w
override def setContentLength(i: Int) = {}
def getCopy: Array[Byte] = sos.getCopy
}
最後Scalatra的行動是由完成後handle
方法需要附加標題的護理使用回調ScalatraBase.onRenderedComplete
。
trait SignedResponseSupport extends Handler {
self: ScalatraBase =>
abstract override def handle(req: HttpServletRequest, res: HttpServletResponse): Unit = {
withRequestResponse(req, res) {
val sosc = new ServletOutputStreamCopier(res.getOutputStream)
val w = new PrintWriter(sosc)
val wrapped = new ResponseCopier(response,sosc ,w)
ScalatraBase.onRenderedCompleted { _ =>
w.flush()
w.close()
val password = "secret-password"
val signature = signResponseBody(wrapped.getCopy, password)
wrapped.addHeader("X-Response-Signature", signature)
}
}
super.handle(req, wrapped)
}
def signResponseBody(body: Array[Byte], password: String): String = {
/*signing goes here*/
}
}