NodeJS 的新手通常會發現它的 API 很難掌握。幸運的是,許多開發人員已經創建了可以更輕鬆地使用 Node.js 的框架。 Connect 就是這樣一個框架。它位於 Node 的 API 之上,在舒適性和控制性之間劃定了界限。
將 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
並新增 <h1></h1>
元素。重新啟動伺服器(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 和會話是任何 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 交互之前,我只会再提一些。
您刚刚学习了如何使用 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:3000 This is not a POST request (probably a GET request) $ curl -X POST http://localhost:3000 This 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.js module.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 框架連接的詳細內容。更多資訊請關注PHP中文網其他相關文章!