1+ 'use strict'
2+
13const CacheManager = require ( 'cache-manager' )
24const iu = require ( 'middleware-if-unless' ) ( )
35const { parse : cacheControl } = require ( '@tusbar/cache-control' )
@@ -11,6 +13,7 @@ const X_CACHE_HIT = 'x-cache-hit'
1113const CACHE_ETAG = 'etag'
1214const CACHE_CONTROL = 'cache-control'
1315const CACHE_IF_NONE_MATCH = 'if-none-match'
16+ const DATA_POSTFIX = '-d'
1417
1518const middleware = ( opts ) => async ( req , res , next ) => {
1619 try {
@@ -30,43 +33,54 @@ const middleware = (opts) => async (req, res, next) => {
3033 // ref cache key on req object
3134 req . cacheKey = key
3235
33- // try to retrieve cached response
34- const cached = await get ( mcache , key )
36+ // try to retrieve cached response metadata
37+ const metadata = await get ( mcache , key )
3538
36- if ( cached ) {
39+ if ( metadata ) {
3740 // respond from cache if there is a hit
38- let { status, headers, data } = JSON . parse ( cached )
41+ const { status, headers, encoding } = JSON . parse ( metadata )
3942
4043 // pre-checking If-None-Match header
4144 if ( req . headers [ CACHE_IF_NONE_MATCH ] && req . headers [ CACHE_IF_NONE_MATCH ] === headers [ CACHE_ETAG ] ) {
4245 res . setHeader ( 'content-length' , '0' )
4346 res . statusCode = 304
4447 res . end ( )
4548
46- return // exit because client cache state matches
47- }
48-
49- if ( typeof data === 'object' && data . type === 'Buffer' ) {
50- data = Buffer . from ( data . data )
51- }
52- headers [ X_CACHE_HIT ] = '1'
49+ return
50+ } else {
51+ // try to retrieve cached response data
52+ const payload = await get ( mcache , key + DATA_POSTFIX )
53+ if ( payload ) {
54+ let { data } = JSON . parse ( payload )
55+ if ( typeof data === 'object' && data . type === 'Buffer' ) {
56+ data = Buffer . from ( data . data )
57+ }
58+ headers [ X_CACHE_HIT ] = '1'
5359
54- // set cached response headers
55- Object . keys ( headers ) . forEach ( header => res . setHeader ( header , headers [ header ] ) )
60+ // set cached response headers
61+ Object . keys ( headers ) . forEach ( header => res . setHeader ( header , headers [ header ] ) )
5662
57- // send cached payload
58- req . cacheHit = true
59- res . statusCode = status
60- res . end ( data )
63+ // send cached payload
64+ req . cacheHit = true
65+ res . statusCode = status
66+ res . end ( data , encoding )
6167
62- return
68+ return
69+ }
70+ }
6371 }
6472
6573 onEnd ( res , ( payload ) => {
6674 if ( payload . headers [ X_CACHE_EXPIRE ] ) {
6775 // support service level expiration
6876 const keysPattern = payload . headers [ X_CACHE_EXPIRE ] . replace ( / \s / g, '' )
69- const patterns = keysPattern . split ( ',' )
77+ const patterns = keysPattern . split ( ',' ) . map ( pattern =>
78+ pattern . endsWith ( '*' ) ? pattern : [ pattern , pattern + DATA_POSTFIX ] )
79+ . reduce ( ( acc , item ) => {
80+ acc . push ( ...item )
81+
82+ return acc
83+ } , [ ] )
7084 // delete keys on all cache tiers
7185 patterns . forEach ( pattern => opts . stores . forEach ( store => getKeys ( store , pattern ) . then ( keys => mcache . del ( keys ) ) ) )
7286 } else if ( payload . headers [ X_CACHE_TIMEOUT ] || payload . headers [ CACHE_CONTROL ] ) {
@@ -92,7 +106,10 @@ const middleware = (opts) => async (req, res, next) => {
92106 payload . headers [ CACHE_ETAG ] = Math . random ( ) . toString ( 36 ) . substring ( 2 , 16 )
93107 }
94108
95- // cache response
109+ // cache response data
110+ mcache . set ( req . cacheKey + DATA_POSTFIX , JSON . stringify ( { data : payload . data } ) , { ttl } )
111+ delete payload . data
112+ // cache response metadata
96113 mcache . set ( req . cacheKey , JSON . stringify ( payload ) , { ttl } )
97114 }
98115 } )
0 commit comments