diff --git a/Readme.md b/Readme.md index 037ee6f..e90c5ba 100644 --- a/Readme.md +++ b/Readme.md @@ -138,7 +138,7 @@ response.location('/foo') let html = fs.readFileSync('./index.html') response.render(html) // send from a html file. -let txt = '

hello doJS

' +let txt = '

hello world

' response.render(txt) response.render("You're not able to here", 401) @@ -189,3 +189,12 @@ response.send(200, 'success', { name: 'foo', age: 16 }, 'blabla') * data `` | `` optional > 向客户端输出内容。 + + +### cookie(key, value, options) + +* key `` +* value `` +* options `` 额外配置[可选] + +> 向客户端写入cookies。 \ No newline at end of file diff --git a/index.js b/index.js index 52d42f1..c95156c 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ import fs from 'iofs' import STATUS_TEXT from './lib/http-code.js' +import { serialize } from './lib/cookie.js' export default class Response { constructor(req, res) { @@ -34,34 +35,6 @@ export default class Response { this.statusCode = code } - /** - * [append 往header插入信息] - * @param {String} key [description] - * @param {String} val [description] - */ - append(key, val) { - if (this.rendered) { - return - } - var prev = this.get(key) - var value - - if (Array.isArray(val)) { - value = val - } else { - value = [val] - } - - if (prev) { - if (Array.isArray(prev)) { - value = prev.concat(val) - } else { - value = [prev].concat(val) - } - } - return this.set(key, value) - } - /** * [redirect 页面跳转] * @param {String} url [要跳转的URL] @@ -148,8 +121,14 @@ export default class Response { return } if (typeof code !== 'number') { - msg = code + '' - code = 400 + if (typeof code === 'object') { + data = code + code = 200 + msg = STATUS_TEXT[code] + } else { + msg = code + '' + code = 400 + } } else if (typeof msg === 'object') { data = msg code = code || 200 @@ -222,4 +201,62 @@ export default class Response { } return this } + + /** + * [append 往header插入信息] + * @param {String} key [description] + * @param {String} val [description] + */ + append(key, val) { + if (this.rendered) { + return + } + var prev = this.get(key) + var value + + if (Array.isArray(val)) { + value = val + } else { + value = [val] + } + + if (prev) { + if (Array.isArray(prev)) { + value = prev.concat(val) + } else { + value = [prev].concat(val) + } + } + return this.set(key, value) + } + + /** + * [set 设置cookie] + * @param {[string]} key + * @param {[string/number]} val + * @param {[object]} opts [设置cookie的额外信息,如域,有效期等] + */ + cookie(key, val, opts = {}) { + //读取之前已经写过的cookie缓存 + var cache = this.get('set-cookie') + if (cache) { + if (!Array.isArray(cache)) { + cache = [cache] + } + } else { + cache = [] + } + + if (cache.length > 0) { + // 如果之前已经写了一个相同的cookie, 则删除之前的 + cache = cache.filter(it => { + let _key = it.split('=')[0].trim() + return key !== _key + }) + } + + cache.push(serialize(key, val, opts)) + + this.set('set-cookie', cache) + } } diff --git a/lib/cookie.js b/lib/cookie.js new file mode 100644 index 0000000..9961225 --- /dev/null +++ b/lib/cookie.js @@ -0,0 +1,78 @@ +/** + * @author yutent + * @date 2020/09/20 15:08:50 + */ + +var KEY_REGEXP = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/ +// var SPLIT_REGEXP = /; */ +var encode = encodeURIComponent +// var decode = decodeURIComponent + +/** + * [serialize 序列化对象] + */ +export function serialize(key, val, opts) { + var pairs = [] + if (!KEY_REGEXP.test(key)) { + return '' + } + + val = encode(val) + opts = opts || {} + + if (val && !KEY_REGEXP.test(val)) { + return '' + } + + pairs.push(key + '=' + val) + + if (opts.hasOwnProperty('expires') && opts.expires) { + // pairs.push('Expires=' + opts.expires.toUTCString()) + // 有效期, 已不建议使用,改用 max-age + if (Date.isDate(opts.expires)) { + opts.maxAge = ~~(opts.expires.getTime() / 1000) + } else { + opts.maxAge = +opts.expires + } + delete opts.expires + } + + if (opts.hasOwnProperty('maxAge') && opts.maxAge) { + //有效期 + opts.maxAge = opts.maxAge + pairs.push('Max-Age=' + opts.maxAge) + } + + if (opts.hasOwnProperty('domain')) { + //域 + if (!KEY_REGEXP.test(opts.domain)) { + return '' + } + pairs.push('Domain=' + opts.domain) + } + + if (opts.hasOwnProperty('path')) { + //目录 + if (!KEY_REGEXP.test(opts.path)) { + return '' + } + + pairs.push('Path=' + opts.path) + } else { + pairs.push('Path=/') + } + + if (opts.httpOnly) { + pairs.push('HttpOnly') + } + + if (opts.secure) { + pairs.push('Secure') + } + + if (opts.firstPartyOnly) { + pairs.push('First-Party-Only') + } + + return pairs.join('; ') +} diff --git a/package.json b/package.json index 9fbf776..769b8fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gm5/response", - "version": "1.2.0", + "version": "1.3.0", "type": "module", "description": "对Http的response进一步封装, 提供常用的API", "main": "index.js",