• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

leizongmin / leizm-connect / #4

pending completion
#4

push

leizongmin
feat: ctx.response支持setCookie & clearCookie

0 of 123 branches covered (0.0%)

Branch coverage included in aggregate %.

16 of 16 new or added lines in 1 file covered. (100.0%)

47 of 383 relevant lines covered (12.27%)

0.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.17
/src/lib/response.ts
1
import { ServerResponse } from "http";
2
import { Context } from "./context";
3
import { sign as signCookie } from "cookie-signature";
1✔
4
import * as cookie from "cookie";
1✔
5

6
export interface CookieOptions extends cookie.CookieSerializeOptions {
7
  /** 是否签名 */
8
  signed?: boolean;
9
}
10

11
export class Response {
1✔
12
  constructor(
13
    public readonly res: ServerResponse,
×
14
    public readonly ctx: Context
×
15
  ) {}
16

17
  /**
18
   * 初始化完成
19
   */
20
  public inited() {}
21

22
  /**
23
   * 设置响应状态码
24
   *
25
   * @param statusCode 响应状态码
26
   */
27
  public setStatus(statusCode: number): this {
28
    this.res.statusCode = statusCode;
×
29
    return this;
×
30
  }
31

32
  /**
33
   * 获取响应头
34
   *
35
   * @param name 名称
36
   */
37
  public getHeader(name: string): string | string[] | number {
38
    return this.res.getHeader(name);
×
39
  }
40

41
  /**
42
   * 获取所有响应头
43
   *
44
   * @param name 名称
45
   */
46
  public getHeaders(): Record<string, string | string[] | number> {
47
    return (
×
48
      (this.res.getHeaders
×
49
        ? this.res.getHeaders()
×
50
        : (this.res as any)._headers) || {}
51
    );
52
  }
53

54
  /**
55
   * 设置响应头
56
   *
57
   * @param name 名称
58
   * @param value 值
59
   */
60
  public setHeader(name: string, value: string | string[] | number): this {
61
    this.res.setHeader(name, value);
×
62
    return this;
×
63
  }
64

65
  /**
66
   * 添加响应头
67
   *
68
   * @param name 名称
69
   * @param value 值
70
   */
71
  public appendHeader(name: string, value: string | string[] | number): this {
72
    let header = this.getHeader(name) as any[];
×
73
    if (!header) {
×
74
      header = [];
×
75
    } else if (!Array.isArray(header)) {
×
76
      header = [header];
×
77
    }
78
    if (Array.isArray(value)) {
×
79
      header = header.concat(value);
×
80
    } else {
81
      header.push(value);
×
82
    }
83
    this.setHeader(name, header);
×
84
    return this;
×
85
  }
86

87
  /**
88
   * 设置响应头
89
   *
90
   * @param headers 响应头
91
   */
92
  public setHeaders(headers: Record<string, string | string[] | number>): this {
93
    for (const name in headers) {
×
94
      this.setHeader(name, headers[name]);
×
95
    }
96
    return this;
×
97
  }
98

99
  /**
100
   * 删除响应头
101
   *
102
   * @param name 名称
103
   */
104
  public removeHeader(name: string): this {
105
    this.res.removeHeader(name);
×
106
    return this;
×
107
  }
108

109
  /**
110
   * 写响应头
111
   *
112
   * @param statusCode 响应状态码
113
   * @param headers 响应头
114
   */
115
  public writeHead(
116
    statusCode: number,
117
    headers: Record<string, string | string[] | number>
118
  ): this {
119
    this.res.writeHead(statusCode, headers);
×
120
    return this;
×
121
  }
122

123
  /**
124
   * 输出数据
125
   *
126
   * @param data 要输出的数据
127
   * @param encoding 字符编码
128
   * @param callback 回调函数
129
   */
130
  public write(
131
    data: string | Buffer | Uint8Array,
132
    encoding?: string,
133
    callback?: () => void
134
  ): boolean {
135
    return this.res.write.apply(this.res, arguments);
×
136
  }
137

138
  /**
139
   * 输出数据并结束
140
   *
141
   * @param data 要输出的数据
142
   * @param encoding 字符编码
143
   * @param callback 回调函数
144
   */
145
  public end(
146
    data: string | Buffer | Uint8Array,
147
    encoding?: string,
148
    callback?: () => void
149
  ): boolean {
150
    return this.res.end.apply(this.res, arguments);
×
151
  }
152

153
  /**
154
   * 响应JSON
155
   * @param data 数据
156
   */
157
  public json(data: any): void {
158
    this.setHeader("Content-Type", "application/json");
×
159
    this.end(JSON.stringify(data));
×
160
  }
161

162
  /**
163
   * 响应HTML页面
164
   * @param str 内容
165
   */
166
  public html(str: Buffer | string): void {
167
    this.setHeader("Content-Type", "text/html");
×
168
    this.end(str);
×
169
  }
170

171
  /**
172
   * 删除Cookie
173
   * @param name 名称
174
   * @param options 选项
175
   */
176
  public clearCookie(name: string, options: CookieOptions = {}) {
×
177
    this.cookie(name, "", { expires: new Date(1), path: "/", ...options });
×
178
  }
179

180
  /**
181
   * 设置Cookie
182
   * @param name 名称
183
   * @param value 值
184
   * @param options 选项
185
   */
186
  public cookie(name: string, value: any, options: CookieOptions = {}) {
×
187
    const opts = { ...options };
×
188
    const secret = (this.ctx.request.req as any).secret;
×
189
    if (opts.signed && !secret) {
×
190
      throw new Error('cookieParser("secret") required for signed cookies');
×
191
    }
192
    let val =
193
      typeof value === "object" ? "j:" + JSON.stringify(value) : String(value);
×
194
    if (opts.signed) {
×
195
      val = "s:" + signCookie(val, secret);
×
196
    }
197
    if ("maxAge" in opts) {
×
198
      opts.expires = new Date(Date.now() + opts.maxAge);
×
199
      opts.maxAge /= 1000;
×
200
    }
201
    if (opts.path == null) {
×
202
      opts.path = "/";
×
203
    }
204
    this.appendHeader("Set-Cookie", cookie.serialize(name, String(val), opts));
×
205
  }
206
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc