我正在尝试为Crystal(特别是Kemal)编写一些工具,我可以看到响应内容类型是text/html
并修改已经写入HTTP::Response
的响应主体它通过将HTML元素注入现有的html响应体来发送给客户端。
我注意到HTTP::Server::Response
是只写的,但Gzip::Writer
之类的东西可以修改正文。
如何在将HTTP::Server::Response
html主体发送到客户端之前对其进行修改?
答案 0 :(得分:1)
它是用Crystal编写的,所以让我们来看看其他人如何做到这一点。
以CompressHandler
为例,基本思路是将响应的IO替换为允许所需控件的内容:
protected override bool OnBackButtonPressed()
{
return !PageUtilities.CanNavigate(this, null);
}
那么我们如何利用它来修改正在编写的响应?
一个天真(和缓慢)的例子就是保持原始输出并提供context.response.output = Gzip::Writer.new(context.response.output, sync_close: true)
# ...
call_next(context)
代替:
IO::Memory
当然,只有当这个处理程序出现在任何将响应转换为非明文的处理程序之前(例如上面的client = context.response.output
io = IO::Memory.new
context.response.output = io
call_next(context)
body = io.to_s
new_body = inject_html(body)
client.print new_body
)时才会有效。
更智能的解决方案将提供一个自定义IO实现,它只包装原始IO,观察写入它的内容并在正确的位置注入它想要注入的内容。可以在CompressHandler
,IO::Delimited
和IO::Sized
等处找到此类包装IO的示例,该模式对于防止不必要的分配非常常见。