亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

是否可以手動緩存整個網頁?

是否可以手動緩存整個網頁?

繁花如伊 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個贊

正如這里已經說過的, 應該在 HttpServletResponse.getOutputStream()/.getWriter() 上調用 .close() 嗎?

您最好為您的 servlet 實現一個包裝器,詳見下文。

https://www.oracle.com/technetwork/java/filters-137243.html#72674


查看完整回答
反對 回復 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 關注
  • 227 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號