Express¶
$ npm install @feathersjs/express --save
@feathersjs/express 模块包含用于Feathers的 Express 框架集成:
Express框架绑定 使Feathers应用程序Express兼容
基于Express的传输, 通过:ref:`api_express_rest`公开服务
An 错误
const express = require('@feathersjs/express');
重要
This page describes how to set up an Express server and REST API. See the REST客户端 how to use this server on the client.
重要
This chapter assumes that you are familiar with Express.
express(app)¶
应用 into a fully Express (4+) compatible application that additionally to Feathers functionality also lets you use the Express API.
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
// Create an app that is a Feathers AND Express application
const app = express(feathers());
注解
@feathersjs/express (express) also exposes the
standard Express middleware:
express.json- A JSON body parserexpress.urlencoded- A URL encoded form body parserexpress.static- To statically host files in a folderexpress.Router- Creates an Express router object
express()¶
If no Feathers application is passed, express() -> app returns a
plain Express application just like a normal call to Express would.
app.use(path, service|mw|[mw])¶
服务. an Express middleware or an array of Express middleware on the given path. If 服务 is passed it will use Feathers registration mechanism, for a middleware function Express.
// Register a service
app.use('/todos', {
get(id) {
return Promise.resolve({ id });
}
});
// Register an Express middleware
app.use('/test', (req, res) => {
res.json({
message: 'Hello world from Express middleware'
});
});
// Register multiple Express middleware functions
app.use('/test', (req, res, next) => {
res.data = 'Step 1 worked';
next();
}, (req, res) => {
res.json({
message: 'Hello world from Express middleware ' + res.data
});
});
app.listen(port)¶
app.listen(port) -> HttpServer will first call Express
app.listen and then
internally also call the .setup([server]).
// Listen on port 3030
const server = app.listen(3030);
server.on('listening', () => console.log('Feathers application started'));
app.setup(server)¶
app.setup(server) -> app is usually called internally by
app.listen but in the cases described below needs to be called
explicitly.
Sub-Apps¶
When registering an application as a sub-app, app.setup(server) has
to be called to initialize the sub-apps services.
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const api = express(feathers())
.configure(express.rest())
.use('/service', myService);
const mainApp = express().use('/api/v1', api);
const server = mainApp.listen(3030);
// Now call setup on the Feathers app with the server
api.setup(server);
小技巧
We recommend avoiding complex sub-app setups because websockets and Feathers built in authentication are not fully sub-app aware at the moment.
HTTPS¶
HTTPS requires creating a separate server in which case
app.setup(server) also has to be called explicitly.
const fs = require('fs');
const https = require('https');
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());
const server = https.createServer({
key: fs.readFileSync('privatekey.pem'),
cert: fs.readFileSync('certificate.pem')
}, app).listen(443);
// Call app.setup to initialize all services and SocketIO
app.setup(server);
Virtual Hosts¶
The vhost Express middleware
can be used to run a Feathers application on a virtual host but again
requires app.setup(server) to be called explicitly.
const vhost = require('vhost');
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());
app.use('/todos', todoService);
const host = express().use(vhost('foo.com', app));
const server = host.listen(8080);
// Here we need to call app.setup because .listen on our virtal hosted
// app is never called
app.setup(server);
express.rest()¶
express.rest registers a Feathers transport mechanism that allows
you to expose and consume 服务 through a
RESTful
API.
This means that you can call a service method through the GET,
POST, PUT, PATCH and DELETE HTTP
methods:
Service method |
HTTP method |
Path |
|---|---|---|
.find() |
GET |
/messages |
.get() |
GET |
/messages/1 |
.create() |
POST |
/messages |
.update() |
PUT |
/messages/1 |
.patch() |
PATCH |
/messages/1 |
.remove() |
DELETE |
/messages/1 |
要通过RESTful API公开服务, 我们必须配置``express.rest``并提供我们自己的身体解析器中间件(通常是标准的`Express 4 body-parser <https://github.com/expressjs/body-parser >`_)使REST``.create``, .update``和.patch``调用解析HTTP正文中的数据.如果你想在* REST处理程序之前添加其他中间件*, 请在注册任何服务之前调用``app.use(middleware)``.
小技巧
身体解析器中间件必须在*任何服务之前注册*.否则, 服务方法将抛出一个``No data provided``或``’first’的第一个参数必须是一个object``错误.
app.configure(express.rest())¶
使用标准格式化程序通过`res.json <http://expressjs.com/en/4x/api.html#res.json>`_发送JSON响应来配置传输提供程序.
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
// Create an Express compatible Feathers application
const app = express(feathers());
// Turn on JSON parser for REST services
app.use(express.json())
// Turn on URL-encoded parser for REST services
app.use(express.urlencoded({ extended: true }));
// Set up REST transport
app.configure(express.rest())
app.configure(express.rest(formatter))¶
默认的REST响应格式化程序是一个中间件, 它将服务检索的数据格式化为JSON.如果你想配置你自己的``formatter``中间件传递``formatter(req, res)``函数.这个中间件可以访问``res.data``, 它是服务返回的数据. `res.format <http://expressjs.com/en/4x/api.html#res.format>`_可用于内容协商.
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());
// Turn on JSON parser for REST services
app.use(express.json())
// Turn on URL-encoded parser for REST services
app.use(express.urlencoded({ extended: true }));
// Set up REST transport
app.configure(express.rest(function(req, res) {
// Format the message as text/plain
res.format({
'text/plain': function() {
res.end(`The Message is: "${res.data.text}"`);
}
});
}))
自定义服务中间件¶
只能在特定服务之前或之后运行的Custom Express中间件可按其应运行的顺序传递给“app.use”.:
const todoService = {
get(id) {
return Promise.resolve({
id,
description: `You have to do ${id}!`
});
}
};
app.use('/todos', ensureAuthenticated, logRequest, todoService, updateData);
在服务之后运行的中间件具有可用的服务调用信息
res.data- 将要发送的数据:doc:服务方法调用的`./hooks`上下文
例如``updateData``可能看起来像这样:
function updateData(req, res, next) {
res.data.updateData = true;
next();
}
小技巧
如果在服务之后在自定义中间件中运行``res.send``并且不调用``next``, 则将跳过其他中间件(如REST格式化程序).这可以用于例如为某些服务方法调用呈现不同的视图.
params¶
在:doc:`./rest`之后注册的所有中间件都可以访问``req.feathers``对象来设置服务方法``params`的属性.:
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const bodyParser = require('body-parser');
const app = express(feathers());
app.configure(express.rest())
.use(bodyParser.json())
.use(bodyParser.urlencoded({extended: true}))
.use(function(req, res, next) {
req.feathers.fromMiddleware = 'Hello world';
next();
});
app.use('/todos', {
get(id, params) {
console.log(params.provider); // -> 'rest'
console.log(params.fromMiddleware); // -> 'Hello world'
return Promise.resolve({
id, params,
description: `You have to do ${id}!`
});
}
});
app.listen(3030);
您可以通过运行示例并访问``http://localhost:3030/todos/test``来查看设置的参数.
避免直接设置``req.feathers = something``, 因为它可能已包含其他Feathers插件所依赖的信息.添加单个属性或使用``Object.assign(req.feathers, something)``是更可靠的选择.
重要
由于Express中间件的顺序很重要, 任何设置服务参数的中间件都必须在*您的服务之前注册*(在`app.configure(services)``或``middleware/index.js`之前的生成应用程序中).
小技巧
Although it may be convenient to set
req.feathers.req = req; to have access to the request object in
the service, we recommend keeping your services as provider
independent as possible. There usually is a way to pre-process your
data in a middleware so that the service does not need to know about
the HTTP request or response.
params.query¶
params.query will contain the URL query parameters sent from the
client. For the REST transport the query string is parsed using the
qs module. For some query string
examples see the 查询
chapter.
重要
服务器和客户端之间只传递``params.query``, 而``params``的其他部分则没有.这是出于安全原因, 因此客户端无法设置``params.user``或数据库选项.你总是可以从``params.query``映射到其他:doc:./ hooks.
例如:
GET /messages?read=true&$sort[createdAt]=-1
将``params.query``设置为
{
"read": "true",
"$sort": { "createdAt": "-1" }
}
小技巧
由于URL只是一个字符串, 因此**将没有类型转换**.这可以在:doc:./hooks`中手动完成, 或者使用`query-types Express中间件来转换布尔和数字类型.
注解
如果请求中的数组包含20个以上的项, 则`qs <https://www.npmjs.com/package/qs>`_ parser隐式`转换<https://github.com/ljharb/qs#解析数组>`_它到索引为键的对象.要扩展此限制, 您可以设置自定义查询解析器:app.set('query parser', str => qs.parse(str, {arrayLimit:1000}))
params.provider¶
对于任何:doc:./services`通过REST:doc:./hooks`这可以用来防止外部用户进行服务方法调用:
app.service('users').hooks({
before: {
remove(context) {
// check for if(context.params.provider) to prevent any external call
if(context.params.provider === 'rest') {
throw new Error('You can not delete a user via REST');
}
}
}
});
params.route¶
请参阅`routing section <#routing>`_.
express.notFound(options)¶
``express.notFound()``返回返回``NotFound``(404)的中间件:doc:./errors.它应该被用作**错误处理程序之前的最后一个中间件**.可以使用以下选项:
verbose: 如果URL应该包含在错误消息中, 则设置为``true``(默认值:false)
// Return errors that include the URL
app.use(express.notFound({ verbose: true });
app.use(errorHandler());
express.errorHandler()¶
``expres.errorHandler``是一个`Express错误处理程序<https://expressjs.com/en/guide/error-handling.html>`_中间件, 它将对REST调用的任何错误响应格式化为JSON(或HTML, 如果例如某人直接在浏览器中点击我们的API)并设置相应的错误代码.
小技巧
你仍然可以使用任何其他Express兼容的`错误中间件<http://expressjs.com/en/guide/error-handling.html>`_ with Feathers.事实上, ``express.errors``只是一个稍微定制的.
重要
就像在Express中一样, 错误处理程序必须在*所有中间件和服务之后注册*.
app.use(express.errorHandler())¶
使用默认配置设置错误处理程序.
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());
// before starting the app
app.use(express.errorHandler())
app.use(express.errorHandler(options))¶
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());
// Just like Express your error middleware needs to be
// set up last in your middleware chain.
app.use(express.errorHandler({
html: function(error, req, res, next) {
// render your error view with the error object
res.render('error', error);
}
}));
app.use(errorHandler({
html: {
404: 'path/to/notFound.html',
500: 'there/will/be/robots.html'
}
}));
小技巧
如果你想以json格式获得响应, 请确保在你的请求中将``Accept``头设置为``application/json``, 否则默认的错误处理程序将返回HTML.
创建新的localstorage服务时, 可以传递以下选项:
``html``(Function | Object)[可选] - 自定义格式化程序函数或包含自定义html错误页面路径的对象.
logger(Function|false) (default:console) - 设置一个logger对象来记录错误(它将是带有``logger.error(error)``的记录器
小技巧
``html``也可以设置为``false``来完全禁用html错误页面, 这样只返回JSON.
路由¶
服务URL中的快速路径占位符将添加到服务``params.route``中.
重要
有关何时以及何时不使用嵌套路由的更多详细信息, 请参阅嵌套路由的常见问题条目<../faq/readme.md#how-do-i-do-nested-or-custom-routes>`_.
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());
app.configure(express.rest())
.use(function(req, res, next) {
req.feathers.fromMiddleware = 'Hello world';
next();
});
app.use('/users/:userId/messages', {
get(id, params) {
console.log(params.query); // -> ?query
console.log(params.provider); // -> 'rest'
console.log(params.fromMiddleware); // -> 'Hello world'
console.log(params.route.userId); // will be `1` for GET /users/1/messages
return Promise.resolve({
id,
params,
read: false,
text: `Feathers is great!`,
createdAt: new Date().getTime()
});
}
});
app.listen(3030);

