为了账号安全,请及时绑定邮箱和手机立即绑定

是否可以手动缓存整个网页?

是否可以手动缓存整个网页?

繁花如伊 2023-06-14 14:42:05
我需要缓存一个网页,然后为了将来的请求,检查缓存(使用 url 作为键),如果找到,则从缓存中返回网页而不是发出请求。我正在使用 Smiley 的 ProxyServlet,servlet 写入 OutputStream 的方法似乎非常适合缓存。我只添加了两行代码:/** * Copy response body data (the entity) from the proxy to the servlet client. * TODO: CACHE entity here for retrieval in filter */protected void copyResponseEntity( HttpResponse proxyResponse, HttpServletResponse servletResponse,        HttpRequest proxyRequest, HttpServletRequest servletRequest ) throws IOException{    HttpEntity entity = proxyResponse.getEntity();    if ( entity != null )    {        String key =  getCurrentUrlFromRequest( servletRequest );  // 1        basicCache.getCache().put( key, proxyResponse.getEntity() ); // 2        OutputStream servletOutputStream = servletResponse.getOutputStream();        entity.writeTo( servletOutputStream );    }}它有点管用,它确实将 HttpEntity 存储在缓存中。但是当我返回到浏览器并再次请求相同的 url 时,当代码返回到我的过滤器中时,我使用 url 作为键获得了 HttpEntity,并将其写入响应,但是我得到了一个“Stream closed “ 错误:java.io.IOException: Stream closed    at java.base/java.util.zip.GZIPInputStream.ensureOpen(GZIPInputStream.java:63) ~[na:na]    at java.base/java.util.zip.GZIPInputStream.read(GZIPInputStream.java:114) ~[na:na]    at java.base/java.io.FilterInputStream.read(FilterInputStream.java:107) ~[na:na]    at org.apache.http.client.entity.LazyDecompressingInputStream.read(LazyDecompressingInputStream.java:64) ~[httpclient-4.5.9.jar:4.5.9]    at org.apache.http.client.entity.DecompressingEntity.writeTo(DecompressingEntity.java:93) ~[httpclient-4.5.9.jar:4.5.9]    at com.myapp.test.foo.filters.TestFilter.doFilter(TestFilter.java:37) ~[classes/:na]我坚持使用这种非常本地化的/手动的/任何您想称之为缓存的东西——我不能使用明显的“只需连接 ehcache/redis/任何东西并让它做它的事情”。因此,虽然我知道那些优秀的缓存可以缓存整个网页,但我不知道它们是否允许我以这种公认的不寻常方式工作。所以我希望 SO 可以告诉我如何完成这项工作。我首先尝试在 ConcurrentHashMap 中连接我的基本缓存,但这也不起作用,所以我想看看我是否可以利用大型缓存枪所拥有的任何魔力,但到目前为止我不能。
查看完整描述

2 回答

?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

课堂上TestFilter,能不能在这一行下个断点调试一下?

HttpEntity page = (HttpEntity) basicCache.getCache().get( url );

底层流可能不处于您实际执行的状态:

page.writeTo( servletOutputStream );

本质上,声明PrintWriter您控制状态,从缓存中获取内容,写入响应,然后关闭编写器。


查看完整回答
反对 回复 2023-06-14
?
慕桂英546537

TA贡献1848条经验 获得超10个赞

查看完整回答
反对 回复 2023-06-14
?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

我想知道为什么所有这些很好的答案都同意包装 HttpServletResponse 而我无法让它工作——我觉得自己像个白痴。它没有用,因为对 wrap 的响应中没有任何内容。


页面内容从一开始就全部在 HttpEntity 中: HttpEntity entity = proxyResponse.getEntity();


在我意识到追逐 servlet 响应/请求不是答案之后,我很幸运地发现:org.apache.http.entity.BufferedHttpEntity


包装一个 HttpEntity 以便您可以重复获取内容),但是它是在正确的对象上进行的。


所以上面的第一个方法只是稍微调整了一下,它仍然代理得很好:


    if ( entity != null )

    {

        String key =  getCurrentUrlFromRequest( servletRequest );

        OutputStream servletOutputStream = servletResponse.getOutputStream();

        BufferedHttpEntity wrapper = new BufferedHttpEntity( entity );

        basicCache.getCache().put( key, wrapper );

        wrapper.writeTo( servletOutputStream );

    }

将 BasicCache 更改为期望一个 String 和一个 BufferedHttpEntity,然后对于后续请求,在过滤器中从缓存中获取 BufferedHttpEntity,完成所有工作的行与上面的最后一行相同:


    if ( null != page )

    {           

        OutputStream servletOutputStream = servletResponse.getOutputStream();

        page.writeTo( servletOutputStream );  // bingo

    }

    else

    {

        filterChain.doFilter( servletRequest, servletResponse );

    }

感谢大家的帮助!


查看完整回答
反对 回复 2023-06-14
  • 2 回答
  • 0 关注
  • 134 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信