node.js - Node.js HTTP 服务器中的参数
问题描述
我正在尝试制作一个类似于 express 的简单 HTTP 模块来帮助学习如何使用 HTTP。
在使用 express 时,我经常使用以下参数:
app.get('/id/:id' (req, res) => {console.log(req.params.id); stuff})
我想知道-
- 是否可以只使用HTTP?
- 如果仅使用 HTTP 无法完成,那么您将如何创建它?
解决方案
是的,但您需要手动处理它。
假设您正在使用节点的http模块,您正在寻找的信息在其中,req.url
但它包括整个 url 路径。
例如,您要解析/id/:id
,而浏览器正在向http://your.server/id/100?something=something
. 那么 的值req.url
将是:
/id/100?something=something
但是,如果您使用net模块从头开始编写 HTTP 模块,那么您需要知道 HTTP 请求的格式。基本上,HTTP 请求看起来像具有以下格式的文本文件:
GET /id/100?something=something HTTP/1.1
Host: your.server
标题部分以双换行符结尾。从技术上讲,它应该是\r\n\r\n
但\n\n
也是可以接受的。您首先需要从协议(上面示例中的 GET,但可以是 POST、PUT 等)和 HTTP 版本号之间的请求的第一行获取 url。
对于任何有兴趣从头开始编写 HTTP 服务器的人,我总是推荐 James Marshall 的优秀文章:https ://www.jmarshall.com/easy/http/ 。它最初是在 90 年代后期编写的,但直到今天我还没有找到更清晰的 HTTP 协议摘要。我自己用它来编写我的第一个 HTTP 服务器。
现在您必须编写代码来100
从字符串中提取 。
如果您是手动执行此操作,而不是尝试编写 Express 之类的框架,则可以这样做:
const matches = req.url.match(/id\/([^\/?]+)/);
const id = matches[1];
如果你想编写一个库来解释/id/:id
模式,你可以做这样的事情(注意:不是优化的实现,它的表达方式也略有不同):
function matchRoute (req, route) {
const [ urlpath, query ] = req.url.split('?'); // separate path and query
const pathParts = urlpath.split('/');
const routeParts = urlpath.split('/');
let params = {};
for (let i=0; i<pathParts.length; i++) {
if (routeParts[i].match(/^:/)) { // if route part starts with ":"
// this is a parameter:
params[routeParts[i].replace(':','')] = pathParts[i];
}
else {
if (routeParts[i] !== urlParts[i]) {
return false; // false means path does not match route
}
}
// if we get here (don't return early) it means
// the route matches the path, copy all found params to req.params:
req.params = params;
return true; // true signifies a match so we should process this route
}
}
// Test:
let req.url = '/id/100';
let result = matchRoute(req, '/id/:id');
console.log(result, req.params); // should print "true, {id:100}"
推荐阅读
- node.js - 预期的 catch() 或返回 [promise/catch-or-return] 并且每个 then() 应该返回一个值或抛出 [promise/always-return]
- python - 如何使用 BeautifulSoup 仅提取某些字段
- android - 如何为来自另一个库的自定义视图设置抗锯齿?
- javascript - 将抽屉元素放置在菜单底部
- laravel - 无法让 Laravel-Filemanager 在远程服务器的子文件夹中工作
- c++ - 链接时如何跟踪库的需求?
- sqlite - 将查询结果设置为默认列值而不使用触发器
- scala - 如何使用 Scala 登录 Play Framework?
- systemd - 'systemd' 杀死普通用户子进程
- git - 签出的版本与 glide.lock 不匹配