Skip to content

Commit af0c440

Browse files
committed
feat: enable cache
1 parent 5eff516 commit af0c440

File tree

4 files changed

+35
-0
lines changed

4 files changed

+35
-0
lines changed

fixtures/html.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>html</title>
7+
<link rel="stylesheet" href="css.css" />
78
</head>
89
<body>
910
html

src/cli.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ const cliOptions = [
2828
defaultValue: false,
2929
usage: `htttp-server --cors`,
3030
},
31+
{
32+
option: '-dc, --disable-cache',
33+
description: 'Disable cache',
34+
defaultValue: false,
35+
usage: `htttp-server -dc`,
36+
},
3137
];
3238

3339
cliOptions.forEach(({ option, description, defaultValue }) => program.option(option, description, defaultValue.toString()));
@@ -45,5 +51,6 @@ const server = new Server({
4551
baseDir: opts.directory,
4652
dataPosition: opts.data,
4753
cors: JSON.parse(opts.cors),
54+
cache: !JSON.parse(opts.disableCache),
4855
});
4956
server.start();

src/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default class Server {
1616
baseDir: string = DEFAULT_BASE_DIR;
1717
data: { [k: string]: ResourceItem[] } = {};
1818
cors: boolean = false;
19+
cache: boolean = true;
1920

2021
constructor(options?: ServerOptions) {
2122
if (options?.port) {
@@ -36,6 +37,9 @@ export default class Server {
3637
if (options?.cors) {
3738
this.cors = true;
3839
}
40+
if (!options?.cache) {
41+
this.cache = false;
42+
}
3943
}
4044

4145
start() {
@@ -89,6 +93,9 @@ export default class Server {
8993
}
9094

9195
private async processFile(file: string, res: Res) {
96+
if (this.cache) {
97+
this.processCache(res, file); // The homepage will not be cached.
98+
}
9299
res.setHeader('Content-Type', `${mine.getType(file) ?? 'text/plain'};charset=utf-8`);
93100
createReadStream(file).pipe(res);
94101
}
@@ -208,4 +215,23 @@ export default class Server {
208215
}
209216
}
210217
}
218+
219+
private async processCache(res: Res, file: string) {
220+
// This method is not recommended for production use. Because this time is server time, not client time, but browsers use client time to adjust if the cache is expired.
221+
// res.setHeader('Expires', new Date(Date.now() + 10 * 1000).toUTCString());
222+
223+
// res.setHeader('Cache-Control', 'no-cache'); <===> res.setHeader('Cache-Control', 'max-age=0');
224+
// res.setHeader('Cache-Control', 'no-store');
225+
// no-cache: The browser will send a request to the server to check if the cache is expired, but the browser has cached the response.
226+
// no-store: The browser will send a request to the server to check if the cache is expired, and the browser has not cached the response.
227+
228+
const stat = await fs.stat(file);
229+
res.setHeader('Last-Modified', stat.mtime.toUTCString());
230+
res.setHeader('Cache-Control', 'max-age=3600');
231+
const ifModifiedSince = res.req?.headers['if-modified-since'];
232+
if (ifModifiedSince && ifModifiedSince === stat.mtime.toUTCString()) {
233+
res.statusCode = 304;
234+
return res.end();
235+
}
236+
}
211237
}

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export interface ServerOptions {
55
baseDir?: string;
66
dataPosition?: string;
77
cors?: boolean;
8+
cache?: boolean;
89
}
910

1011
export type Res = http.ServerResponse<http.IncomingMessage> & {

0 commit comments

Comments
 (0)