restify是我经常用到的node server模块,实际应用时经常因为不熟悉细节用法,需要查看官方文档,比较麻烦。
这次把官方文档扒了一遍,整理此文,侧重不太常用或不太熟悉的用法,方便查找。
restify
create
1 | restify = require 'restify' |
server.use(fn)
传入一个function,该function接收(req,res,next)三个参数
define routes
- server.post
- server.put
- server.get
- server.head
- server.del
define routes parameters
path
or{name:'foo',path:'/foo'}
当提供name
后,可以由next
跳转function(req,res,next)
function(req,res,next)
可选。支持多个处理过程
Hypermedia
1 | server.get {name:'city',path:'cities/:slug'},(req,res,next)-> |
versioned routes
1 | server.get {path:'/foo',version:'1.1'},(req,res,next)-> |
请求时可在http头添加accept-version
字段。
upgrade requests
- http requests contain
Connection: Upgrade
- enable
handleUpgrade
when creating the server
1 | ws = new Watershed() |
content negotiation
默认情况下res.send()
会自动选择content-type
返回,也可以自定义parser
。restify
自身有以下几种三种formatters
对应的content-types
application/json
text/plain
application/octet-stream
1 | server = restify.createServer |
then:
1 | res.setHeader 'content-type','application/foo' |
如果覆盖默认的几种formatters
,会改变priority
优先级,可以设置一个q-value
,例如:1
2
3restify.createServer
formatters:
'application/foo;q=0.9',(req,res,body)->
错误处理
examples:1
2
3
4next err # 返回500
res.send 4xx,new Error('xxx') # 返回指定http状态码
res.send {} # 返回200
next.ifError err # restify 2.1 supports
handle an error condition:1
2
3server.on 'InternalServerError',(req,res,err,cb)->
err._customContent = 'something...'
return cb()
常见错误列表
- BadRequestError (400 bad request)
- UnauthorizedError (401 Unauthorized)
- PaymentRequiredError (402 Payment Required)
- ForbiddenError (403 Forbidden)
- NotFoundError (404 Not Found)
- MethodNotAllowedError (405 Method Not Allowed)
- NotAcceptableError (406 Not Acceptable)
- ProxyAuthenticationRequiredError (407 Proxy Authentication Required)
- RequestTimeoutError (408 Request Time-out)
- ConflictError (409 Conflict)
- GoneError (410 Gone)
- LengthRequiredError (411 Length Required)
- PreconditionFailedError (412 Precondition Failed)
- RequestEntityTooLargeError (413 Request Entity Too Large)
- RequesturiTooLargeError (414 Request-URI Too Large)
- UnsupportedMediaTypeError (415 Unsupported Media Type)
- RequestedRangeNotSatisfiableError (416 Requested Range Not Satisfiable)
- ExpectationFailedError (417 Expectation Failed)
- ImATeapotError (418 I’m a teapot)
- UnprocessableEntityError (422 Unprocessable Entity)
- LockedError (423 Locked)
- FailedDependencyError (424 Failed Dependency)
- UnorderedCollectionError (425 Unordered Collection)
- UpgradeRequiredError (426 Upgrade Required)
- PreconditionRequiredError (428 Precondition Required)
- TooManyRequestsError (429 Too Many Requests)
- RequestHeaderFieldsTooLargeError (431 Request Header Fields Too Large)
- InternalServerError (500 Internal Server Error)
- NotImplementedError (501 Not Implemented)
- BadGatewayError (502 Bad Gateway)
- ServiceUnavailableError (503 Service Unavailable)
- GatewayTimeoutError (504 Gateway Time-out)
- HttpVersionNotSupportedError (505 HTTP Version Not Supported)
- VariantAlsoNegotiatesError (506 Variant Also Negotiates)
- InsufficientStorageError (507 Insufficient Storage)
- BandwidthLimitExceededError (509 Bandwidth Limit Exceeded)
- NotExtendedError (510 Not Extended)
- NetworkAuthenticationRequiredError (511 Network Authentication Required)
- BadDigestError (400 Bad Request)
- BadMethodError (405 Method Not Allowed)
- InternalError (500 Internal Server Error)
- InvalidArgumentError (409 Conflict)
- InvalidContentError (400 Bad Request)
- InvalidCredentialsError (401 Unauthorized)
- InvalidHeaderError (400 Bad Request)
- InvalidVersionError (400 Bad Request)
- MissingParameterError (409 Conflict)
- NotAuthorizedError (403 Forbidden)
- RequestExpiredError (400 Bad Request)
- RequestThrottledError (429 Too Many Requests)
- ResourceNotFoundError (404 Not Found)
- WrongAcceptError (406 Not Acceptable)
自定义错误
1 | util = require 'util' |
events
NotFound
(req,res,cb) url dones not exist.MethodNotAllowed
(req,res,cb) url exist,but no route.VersionNotAllowed
(req,res,cb) route exist,but does not match the version.UnsupportedMediaType
(req,res,cb) route exist, but does not match content-typeafter
(req,res,route,error) after a route handler.when 404/405/Badversion,still be fired,but route will benull
.uncaughtException
when some handler throws an uncaughtException.
server其他属性
name
名称version
default version to user in all routes.log
Object bunyan instanceacceptable
Array(String) list of content-types then server can respond withurl
String Once listen() is called,this will be filled in tieh where the server is running.
server其他方法
address()
wraps node’s address(),returns the bound address.
e.g.1
{ "port": 12346, "family": "IPv4", "address": "127.0.0.1" }
listen(port,[host],[callback])
or listen(path,[callback])
wraps node’s listen()
(path,[callback]) start a local socket server listening for connections on the given path.
close()
wraps node’s close()
pre()
allows you to add in handlers then run before routing occurs.
e.g.1
2
3server.pre (req,res,next)->
res.headers.accept = 'application/jsn'
next()
use()
allows you to add in handlers then run no matter what the route.
Bundled Plugins
内置的多个中间件
Accept header parsing
parses out then Accept
header.
authorization header parsing
parses out then Authorization
header
cors handling plugin
supports tacking CORS
headers into actual
requests.
当添加其他头部信息时
e.g:1
2
3
4server.use restify.CORS
origins:['http://a.com','http://b.com'.'http://c.com:8081'] # defaults to ['*']
credentials:true # defaults to false
headers:['x-foo'] # sets expose-headers
date header parsing
parses out then HTTP Date header(if present) and checks for clock skew(default allowed clock skew is 300s,lite Kerberos).It can pass in a number,whick is interpreted in seconds,to allow for clock skew.server.use restify.dateParser(60)
60s
jsonp support
you should set the queryParser
plugin to run before this.
gzip response
query string parsing
parses the HTTP query string (i.e.,/foo?id=bar&name=mark
)
if use this,the parsed content will in req.query
, and params are merged into req.params
.you can disable by passing in mapParams:false
in the options object:server.use restify.queryParser({mapParams:false)})
body parsing (JSON/URL-encoded/multipart form)
Blocks your chain on reading and parsing the HTTP request body.Switchs on Content-Type
and does then appropriate logic.application/json
,application/x-www-form-urlencoded
and multipart/form-data
are currently supported.1
2
3
4
5
6
7
8
9
10
11
12
13
14server.use restify.bodyParser
maxBodySize:0 # then maximum size in bytes allowed in the HTTP body.
mapParams:true # if req.params shoud be filled with parsed parameters form HTTP body
mapFiles:false # if req.params should be filled with the contents of files sent through a multipart request.
overrideParams:false
multipartHandler:(part)->
part.on 'data',(data)->
# do something with the multipart data
multipartFileHandler:(part)->
part.on 'data',(data)->
# do something with the multipart file data
keepExtensions:false
uploadDir: os.tmpdir()
multiples: true
static file serving
1 | server.get '/',restify.serveStatic |
throttling 流量限制
1 | server.use restify.throttle |
conditional request handling
1 | server.use (req,res,next)-> |
audit logger
1 | server.on 'after',restify.auditLogger |
request API
header(key,[defaultValue])
req.header 'Accept','*/*'
accepts(type)
req.accepts 'html
html,text/html,text/plain,application/json
is(type)
req.is 'html'
,req.is 'json
isSceure() 是否加密
isChunked() 是否分块
isKeepAlive() 是否kept alive
log
1 | myHandler = (req,res,next)-> |
getLogger(component)
shorthand to grab a new bunyan instance then is a child component of the one restify has:1
log = req.getLogger 'MyFoo'
time()
请求到达的时候,单位ms
startHandlerTimer(handlerName) 开始一个计时器
endHandlerTimer(handlerName) 结束一个计时器
Properties
contentLength
NumbercontentType
Stringhref
String url.parse(req.url) hreflog
Object bunyan logger you can piggyback onid
string A unique request id (x-request-id)path
String cleaned up URL path
response API
header(key,value)
1 | res.header 'Content-Length',123 |
charSet(type)
Appends the provided character set to the response’s Content-Type
1
res.charSet 'utf-8'
Will change the normal json Content-Type
to application/json;charset=utf-8
cache([type],[options])
Sets then cache-control header.type
defaults to _public_
,and options curretly only taks maxAge
.
status(code)
Sets then response statusCode.e.g.res.cache()
send([status],body)
You can use send()
to wrap up all the usual writeHead()
,write()
,end()
calls on the HTTP API of node.1
2
3res.send hello:'world'
res.send 201,{hello:'world'}
res.send new BadRequestError 'meh'
json([status],body)
等同于以下代码:1
2res.contentType = 'json'
res.send {hello:'world'}
properties
code
Number HTTP status codecontentLength
Number short hand for the header content-lengthcontentType
String short hand for the header content-typeheaders
Object response headersid
String A unique request id (x-request-id)
设置默认headers
You can change what headers restify sends by default by setting the top-level property defaultResponseHeaders
.This should be a function that taks one argument data
,whick is the already serialized response body.data
can be either a String or Buffer (or null). The this
object will be the response itself.1
2
3
4restify = require 'restify'
restify.defaultResponseHeaders = (data)->
this.header 'Server','hello world.'
restify.defaultResponseHeaders = false # disable altogether.
DTrace
Dynamic Tracing 动态跟踪1
2
3
4
5
6$ dtrace -l -P restify*
ID PROVIDER MODULE FUNCTION NAME
24 restify38789 mod-88f3f88 route-start route-start
25 restify38789 mod-88f3f88 handler-start handler-start
26 restify38789 mod-88f3f88 handler-done handler-done
27 restify38789 mod-88f3f88 route-done route-done
Client API
restify
支持3种client
JsonClient
sends and expects application/jsonStringCLient
sends url-encoded request and expects text/plainHttpClient
thin wrapper over node’s http/https libraries.
JsonClient
createJsonClient(options)
1 | client = restify.createJsonClient |
options:
accept
StringconnectTimeout
Number Amount of time to wait for a socket.requestTimeout
Number Amount of time to wait for the request to finishdtrace
Object node-dtrace-provider handlegzip
Object will compress data when sent usingcontent-encodeing:gzip
headers
Object HTTP headers to set in all requests.log
Object bunyan instanceretry
Object options to provide to node-retry;’false’ disables retry.defaults to 4 resties.signRequest
Function synchronous callback for interpossing headers before request is sent.url
String Fully-qualified URL to connect to.userAgent
String UAversion
String semver string to set the accpet-version.
get(path,callback)
1 | client.get '/foo/bar',(err,req,res,obj)-> |
head(path,callback)
类似get
方法,但不传入obj
参数
post(path,object,callback)
put(path,object,callback)
del(path,callback)
StringClient
createStringClient(options)
get(path,callback)
head(path,callback)
post(path,object,callback)
put(path,object,callback)
del(path,callback)
HttpClient
HttpClient
是restify提供的最底层的client.只是在node’s http/https modules中添加了部分语法糖。
basicAuth(username,password)
1 | client.basicAuth 'mark','mysupersecretpassword' |