将 connect 视为中间件堆栈。对于每个请求,connect 都会通过中间件层进行过滤,每个中间件层都有机会处理 http 请求。当 t.j. holowaychuk 宣布了 connect,他说有两种类型的中间件。第一个是过滤器。
过滤器处理请求,但不响应它(想想服务器日志记录)。
另一种类型是提供者,它响应请求。您可以根据需要合并任意数量的中间件;请求会遍历每一层,直到其中一个中间件响应该请求。
基本语法首先,您需要通过npm安装connect包:
npm install connect
现在创建一个server.js文件,并添加以下代码:
var connect = require(connect);
connect 变量是一个返回新 connect 应用程序的函数。因此,我们的下一步是创建该应用程序:
var app = connect();
您不需要为大多数应用程序创建 app 变量。创建应用程序涉及的函数(connect() 和 use()) 是可链接的:
connect() .use(/* middleware */) .use(/* middleware */) .listen(3000);
use() 函数向应用程序添加了一层中间件,而 listen() 函数告诉我们的应用程序开始接受指定端口(本例中为 3000)上的连接。让我们从简单的事情开始:日志记录。仅使用日志记录中间件的 connect 应用程序的代码相当简单:
connect() .use(connect.logger()) .listen(3000);
默认情况下,node 会解析很少的传入请求。
将该代码添加到您的文件中,然后通过运行 node server.js 启动服务器。导航到浏览器中的任何路径,并忽略“无法获取...”结果。我们对服务器发送回浏览器的内容不感兴趣;我们对服务器的日志感兴趣。查看终端,您将看到您的请求日志。请务必查看记录器文档以获取有关其其他功能和自定义的信息。
那是一个过滤器;现在让我们看看一个提供者。最简单的提供者是静态提供者;它提供指定文件夹中的静态文件。这是它的语法:
.use(connect.static(__dirname + /public)
你大概可以猜到 node 的 __dirname 变量的用途:它是当前目录的路径。该中间件静态地提供当前目录中 public 文件夹中的任何内容。因此,创建 public/page.html 并添加 元素。重新启动服务器(node server.js),然后在浏览器中导航到 localhost:3000/page.html。您应该在浏览器中呈现 page.html。
现在让我们快速浏览一下 connect 的其他一些中间件选项。
解析请求体默认情况下,node 会解析很少的传入请求,但如果需要处理更复杂的情况,可以合并多个不同的过滤器来解析请求。有四个过滤器:
connect.json() 解析 json 请求体(其中 content-type 为 application/json)。connect.urlencoded() 解析 x-ww-form-urlencoded 请求体。connect.multipart() 解析 multipart/form-data 请求体。connect.bodyparser() 是启用上述所有三个功能的快捷方式。使用任何这些过滤器都可以让您通过 request.body 访问已解析的正文(我们很快就会讨论如何获取 request 对象)。
我认为这些过滤器是如何通过 connect 细粒度控制的一个很好的例子。您可以使用很少的处理来简化您的应用程序。
解析 cookie 和会话cookie 和会话是任何 web 应用程序的重要组成部分,有多个中间件可以帮助管理它们。 connect.cookieparser() 会为您解析 cookie,您可以通过 request.cookies 对象检索 cookie 及其值。如果您将 connect.session() 过滤器添加到您的应用程序中,这会更有用。此过滤器要求 cookie 解析器已就位。这是一个小例子:
connect() .use(connect.cookieparser()) .use(connect.session({ secret: 'some secret text', cookie: { maxage: 30000 }})) .use(function(req, res) { var sess = req.session, url = req.url.split(/); if (url[1] == name && url[2]) { sess.name = url[2]; res.end(name saved: + url[2]); } else if (sess.name) { res.write(session-stored name: + sess.name); res.end(stored for another: + (sess.cookie.maxage / 1000) + seconds); } else { res.end(no stored name; go to /name/{name} to save a name); }}).listen(3000);
您编写的每个中间件函数都需要将请求传递到 next 层或响应请求。
在 cookieparser 之后,我们包含 session 过滤器并传递给它两个选项:
secret 创建一个签名 cookie,用于跟踪会话。cookie.maxage 定义其生命周期(以毫秒为单位);此代码中的 30000 是 30 秒。在最后的 use() 调用中,我们传递一个响应请求的函数。我们使用 request 对象中的两个属性:req.session 用于会话数据,req.url 用于请求 url。
如果应用程序收到对 /name/some_name 的请求,则它将值 some_name 存储在 req.session.name 中。会话中存储的任何内容都可以在会话期间的后续请求中检索。对 /name/other 发出的任何请求都会替换会话变量,对其他 url 的任何请求都会输出会话变量的值和会话剩余时间。
因此,您可以导航到 localhost:3000/name/your_name,然后转到 localhost:3000 查看 your_name。刷新页面几次并观察秒数倒计时。当会话过期时,您将看到默认的“未存储名称”消息。
我提到 cookieparser 过滤器必须位于 session 之前。
包含的顺序对于中间件很重要,因为请求是按顺序从一层传递到另一层的。
由于session需要解析后的cookie数据,因此请求必须先经过cookieparser,然后再经过session。
我可以解释所有其他内置中间件,但在我们编写自己的代码与 connect 交互之前,我只会再提一些。
compress:gzip压缩中间件basicauth:基本http认证目录:列出中间件的目录errorhandler:灵活的错误处理程序编写自己的中间件您刚刚学习了如何使用 connect 编写自己的代码。这是基本语法:
.use(function (req, res, next) {})
函数的三个参数很重要;它们提供了通往外部世界的通道。 req 参数当然是请求对象,res 是响应。第三个参数 next 是使函数在中间件堆栈中正常运行的关键。它是一个将请求传递到堆栈中的下一个中间件的函数。请参阅此示例:
connect() .use(function (req, res, next) { if (req.method === 'post') { res.end(this is a post request); } else { next(); } }) .use(function (req, res) { res.end(this is not a post request (probably a get request)); }).listen(3000);
这段代码使用了两个中间件函数。第一个函数检查请求方法以查看是否是 post 请求。如果是,它就会这样回应。否则,我们调用 next() 并将请求传递给下一个函数,该函数无论如何都会响应。使用 curl 在终端中测试两层:
$ curl http://localhost:3000this is not a post request (probably a get request)$ curl -x post http://localhost:3000this is a post request
如果您不喜欢该终端,请尝试这个有用的 chrome 插件。
重要的是要记住,您编写的每个中间件函数都需要将请求传递到 next 层或响应请求。如果您的函数分支(通过 if 语句或其他条件),您必须确保每个分支都会传递请求或响应请求。如果您的应用程序在浏览器中挂起,可能是因为您忘记在某个时刻调用 next()。
现在,那些 request 和 response 参数怎么样?这些与您在使用“原始”节点服务器时收到的请求和响应对象完全相同:
require(http).createserver(function (req, res) { // ...}).listen(3000);
如果您以前没有使用过 node 的服务器 api,让我向您展示可以用它做什么。
请求对象request对象实际上是一个http.incomingmessage对象,其重要属性如下::
req.method 告诉您使用了哪种 http 方法。req.url 告诉您请求的是哪个 url。req.headers 是一个包含标头名称和值的对象。req.query 是一个包含查询字符串中任何数据的对象(要解析它,您需要 connect.query() 中间件)。req.body 是表单数据的对象(您需要一些正文解析中间件)。req.cookies是cookie数据的对象(需要cookie解析)。req.session 是会话数据的对象(同样,您需要 cookie 解析和会话中间件)您可以使用以下代码查看所有这些工作:
connect() .use(connect.query()) // gives us req.query .use(connect.bodyparser()) // gives us req.body .use(connect.cookieparser()) // for session .use(connect.session({ secret: asdf })) // gives us req.session .use(function (req, res) { res.write(req.url: + req.url + \n\n); res.write(req.method: + req.method + \n\n); res.write(req.headers: + json.stringify(req.headers) + \n\n); res.write(req.query: + json.stringify(req.query) + \n\n); res.write(req.body: + json.stringify(req.body) + \n\n); res.write(req.cookies: + json.stringify(req.cookies) + \n\n); res.write(req.session: + json.stringify(req.session)); res.end(); }).listen(3000);
要查看其中每个值的某些内容,您需要使用查询字符串将一些数据发布到 url。以下内容应该足够了:
curl -x post -d name=yourname http://localhost:3000/some/url?some=data
通过这七个属性,您几乎可以管理收到的任何请求。我不认为经常使用预告片(根据我的经验,我从未见过它们),但是如果您希望在请求中使用预告片,则可以使用 req.trailers (预告片就像标头一样,但位于正文之后)。
那么,你的回应呢?
响应对象原始响应对象不提供库(如 express)为您提供的便利。例如,您无法通过对预制模板的简单渲染调用来响应 - 至少默认情况下不能。响应中的假设很少,因此您需要填写所有小细节。
我们将从状态代码和响应标头开始。您可以使用 writehead() 方法一次性设置所有这些。以下是 node 文档中的示例:
var body = 'hello world';response.writehead(200, { 'content-length': body.length, 'content-type': 'text/plain' });
如果需要单独设置header,可以使用setheader()方法:
connect() .use(function (req, res) { var accept = req.headers.accept.split(,), body, type; console.log(accept); if (accept.indexof(application/json) > -1) { type = application/json; body = json.stringify({ message: hello }); } else if (accept.indexof(text/html) > -1) { type = text/html; body = <h1> hello! </h1>; } else { type = text/plain; body = hello!; } res.statuscode = 200; res.setheader(content-type, type); res.end(body); }).listen(3000);
将此代码添加到文件中,启动服务器并从浏览器请求它。你有 html!现在运行:
curl http://localhost:3000
您将收到纯文本。对于 json,请尝试以下操作:
curl -h accept:application/json http://localhost:3000
全部来自同一个 url!
如果您需要知道已经设置了哪些标头,请使用 res.getheader(name) 。您还可以使用 res.removeheader(name) 删除标头。
当然,没有正文的响应是没有用的。正如您在本教程中所看到的,您可以使用 res.write() 方法将数据块写入正文。它接受字符串或缓冲区对象作为参数。如果是字符串,第二个参数是编码类型(默认为utf8)。
res.end() 方法关闭主体,但您可以向其传递数据以写入响应流。这在您只需要输出一行的情况下非常有用。
第三方中间件在普通的旧 node 和 connect 中响应较大的 html 主体有些困难。这是将第三方中间件加入其中的好地方。您可以在 connect github wiki 上找到第三方中间件的列表。例如,我们将使用 connect-jade 包,它允许我们渲染 jade 视图。
首先,安装connect-jade:
npm install connect-jade
接下来,需要并将其添加为中间件。您需要设置一些默认值:
var connect = require(connect), connectjade = require(connect-jade);connect() .use(connectjade({ root: __dirname + /views, defaults: { title: myapp } })) .use(function (req, res) { res.render(index, { heading: welcome to my app }); }).listen(3000);
将根目录设置为包含视图文件的目录。您还可以设置 defaults;这些是每个视图中可用的变量,除非我们稍后在调用 render() 时覆盖它们。
此代码中的最后一个函数调用 res.render()。该方法由 connect-jade 包提供。
它接受的第一个参数是要渲染的视图的名称。
它是视图的路径,无我们在添加中间件时定义的路径,无 jade 文件扩展名。对于这段代码,我们需要一个 views/index.jade 模板来渲染。我们会保持简单:
html head title= title body h1= heading
如果您不熟悉jade,我们会缩进标签名称来创建html 结构。等号检索 javascript 变量的值。这些变量来自我们设置的 defaults ,加上传递给 res.render() 的(可选)第二个参数对象。
还有许多其他第三方中间件,但它们的工作原理彼此相似。您可以通过 npm 安装它们、需要它们并将它们付诸实践。
模块作为中间件如果你深入研究 connect 的工作原理,你会发现每一层实际上都是一个 node 模块——这是一个非常智能的设计。如果您将 connect 用于大型应用程序,那么以 node 模块格式编写代码将是理想的选择。您可能有一个 app.js 文件,如下所示:
// app.jsmodule.exports = function (req, res, next) { res.end(this comes from a module);};
在你的 server.js 中:
var connect = require(connect), app = require(./app);connect() .use(app) .listen(3000);
结论如果您想要一个适合初学者的库来轻松构建大型 web 应用程序,那么 connect 不是您的解决方案。 connect 旨在成为原始 node api 之上的一个薄层,让您可以完全控制服务器应用程序。如果你想要更多,我推荐 express(顺便说一下,是同一个人做的)。除此之外,connect 是一个出色的、可扩展的 node web 应用程序库。
以上就是与 connect 框架连接的详细内容。
