2020-09-16 16:01:46 +08:00
|
|
|
/**
|
|
|
|
* @author yutent<yutent.io@gmail.com>
|
|
|
|
* @date 2020/09/16 14:52:58
|
|
|
|
*/
|
|
|
|
|
2020-09-21 16:22:46 +08:00
|
|
|
import fs from 'iofs'
|
2020-09-20 16:27:35 +08:00
|
|
|
import STATUS_TEXT from './lib/http-code.js'
|
2020-09-16 16:01:46 +08:00
|
|
|
|
|
|
|
export default class Response {
|
|
|
|
constructor(req, res) {
|
|
|
|
this.origin = { req, res }
|
|
|
|
this.rendered = false
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [error http 错误显示]
|
|
|
|
* @param {Number} code [http错误码]
|
|
|
|
* @param {String} msg [错误提示信息]
|
|
|
|
*/
|
|
|
|
error(msg, code = 500) {
|
|
|
|
if (this.rendered) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
msg = msg || STATUS_TEXT[code]
|
|
|
|
|
|
|
|
this.status(code)
|
|
|
|
this.set('Content-Type', 'text/html; charset=utf-8')
|
|
|
|
this.end(
|
|
|
|
`<fieldset><legend>Http Status: ${code}</legend><pre>${msg}</pre></fieldset>`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
status(code = 404) {
|
|
|
|
this.statusCode = code
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [append 往header插入信息]
|
|
|
|
* @param {String} key [description]
|
|
|
|
* @param {String} val [description]
|
|
|
|
*/
|
|
|
|
append(key, val) {
|
|
|
|
if (this.rendered) {
|
|
|
|
return
|
|
|
|
}
|
2020-09-20 16:27:35 +08:00
|
|
|
var prev = this.get(key)
|
|
|
|
var value
|
|
|
|
|
|
|
|
if (Array.isArray(val)) {
|
|
|
|
value = val
|
|
|
|
} else {
|
|
|
|
value = [val]
|
|
|
|
}
|
2020-09-16 16:01:46 +08:00
|
|
|
|
|
|
|
if (prev) {
|
|
|
|
if (Array.isArray(prev)) {
|
|
|
|
value = prev.concat(val)
|
|
|
|
} else {
|
2020-09-20 16:27:35 +08:00
|
|
|
value = [prev].concat(val)
|
2020-09-16 16:01:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.set(key, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [redirect 页面跳转]
|
|
|
|
* @param {String} url [要跳转的URL]
|
|
|
|
* @param {Boolean} f [是否永久重定向]
|
|
|
|
*/
|
|
|
|
redirect(url, f = false) {
|
|
|
|
if (this.rendered) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (!/^(http[s]?|ftp):\/\//.test(url)) {
|
|
|
|
url = '//' + url
|
|
|
|
}
|
|
|
|
this.set('Location', url)
|
|
|
|
this.status(f ? 301 : 302)
|
|
|
|
this.end('')
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [location 页面跳转(前端的方式)]
|
|
|
|
*/
|
|
|
|
location(url) {
|
|
|
|
var html = `<html><head><meta http-equiv="refresh" content="0;url=${url}"></head></html>`
|
|
|
|
if (this.rendered) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
this.render(html)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 以html格式向前端输出内容
|
|
|
|
render(data, code) {
|
|
|
|
if (this.rendered) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
data += ''
|
|
|
|
data = data || STATUS_TEXT[code]
|
|
|
|
this.set('Content-Type', 'text/html')
|
|
|
|
this.set('Content-Length', Buffer.byteLength(data))
|
|
|
|
if (code) {
|
|
|
|
this.status(code)
|
|
|
|
}
|
|
|
|
this.end(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 文件下载
|
2020-09-21 16:22:46 +08:00
|
|
|
sendfile(target, filename) {
|
2020-09-16 16:01:46 +08:00
|
|
|
if (this.rendered) {
|
|
|
|
return
|
|
|
|
}
|
2020-09-21 16:22:46 +08:00
|
|
|
var data
|
|
|
|
|
2020-09-16 16:01:46 +08:00
|
|
|
this.set('Content-Type', 'application/force-download')
|
|
|
|
this.set('Accept-Ranges', 'bytes')
|
|
|
|
this.set('Content-Disposition', `attachment;filename="${filename}"`)
|
2020-09-21 16:22:46 +08:00
|
|
|
|
|
|
|
if (Buffer.isBuffer(target)) {
|
|
|
|
data = target
|
|
|
|
} else {
|
|
|
|
if (typeof target === 'string') {
|
|
|
|
var stat = fs.stat(target)
|
|
|
|
if (stat.isFile()) {
|
|
|
|
this.set('Content-Length', stat.size)
|
|
|
|
fs.origin.createReadStream(target).pipe(this.origin.res)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data = Buffer.from(target + '')
|
|
|
|
}
|
|
|
|
|
|
|
|
this.set('Content-Length', data.length)
|
2020-09-16 16:01:46 +08:00
|
|
|
this.end(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [send json格式输出]
|
|
|
|
* @param {Num} code [返回码]
|
|
|
|
* @param {Str} msg [提示信息]
|
|
|
|
* @param {Str/Obj} data [额外数据]
|
|
|
|
* @param {Str} callback [回调函数名]
|
|
|
|
*/
|
|
|
|
send(code = 200, msg = 'success', data = null, callback = null) {
|
|
|
|
var output
|
|
|
|
|
|
|
|
if (this.rendered) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (typeof code !== 'number') {
|
|
|
|
msg = code + ''
|
|
|
|
code = 400
|
|
|
|
} else if (typeof msg === 'object') {
|
|
|
|
data = msg
|
|
|
|
code = code || 200
|
|
|
|
msg = STATUS_TEXT[code] || 'success'
|
|
|
|
}
|
|
|
|
|
|
|
|
output = { code, msg, data }
|
|
|
|
output = JSON.stringify(output)
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
callback = callback.replace(/[^\w\-\.]/g, '')
|
|
|
|
output = callback + '(' + output + ')'
|
|
|
|
}
|
|
|
|
|
|
|
|
this.set('Content-Type', 'application/json')
|
|
|
|
this.set('Content-Length', Buffer.byteLength(output))
|
|
|
|
|
|
|
|
// 只设置200以上的值
|
|
|
|
if (code && code > 200) {
|
|
|
|
this.status(code)
|
|
|
|
}
|
|
|
|
|
|
|
|
this.end(output)
|
|
|
|
}
|
|
|
|
|
|
|
|
end(buf) {
|
|
|
|
var code = 200
|
|
|
|
if (this.rendered) {
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
if (this.statusCode) {
|
|
|
|
code = this.statusCode
|
|
|
|
delete this.statusCode
|
|
|
|
}
|
|
|
|
this.rendered = true
|
|
|
|
this.origin.res.writeHead(code, STATUS_TEXT[code])
|
|
|
|
this.origin.res.end(buf || '')
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [get 读取已写入的头信息]
|
|
|
|
*/
|
|
|
|
get(key) {
|
|
|
|
return this.origin.res.getHeader(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [set 设置头信息]
|
|
|
|
*/
|
|
|
|
set(key, val) {
|
|
|
|
if (this.rendered) {
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
if (arguments.length === 2) {
|
2020-09-20 16:27:35 +08:00
|
|
|
var value = Array.isArray(val) ? val.map(String) : String(val)
|
2020-09-16 16:01:46 +08:00
|
|
|
|
2020-09-20 16:27:35 +08:00
|
|
|
if (
|
|
|
|
key.toLowerCase() === 'content-type' &&
|
|
|
|
typeof value === 'string' &&
|
|
|
|
value.indexOf('charset') < 0
|
|
|
|
) {
|
2020-09-16 16:01:46 +08:00
|
|
|
value += '; charset=utf-8'
|
|
|
|
}
|
|
|
|
|
|
|
|
this.origin.res.setHeader(key, value)
|
|
|
|
} else {
|
|
|
|
for (let i in key) {
|
|
|
|
this.set(i, key[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
}
|