发布于 2026-01-06 1 阅读
0

从零开始使用 NodeJS 创建基本的 HTTP 服务器

从零开始使用 NodeJS 创建基本的 HTTP 服务器


在本博客中,我们将从头开始创建一个 HTTP 服务器来处理 GET、POST、PUT、DELETE 请求方法类型。

为了使代码正常运行,我们需要在机器上安装 Node.js。我们将使用 Node.js自带的“ http ”模块来获取请求和响应对象,不会使用任何其他自定义库。

创建 HTTP 服务器的步骤

  1. 使用http模块创建服务器并添加监听器。
  2. 对请求进行必要的录入检查
  3. 提取请求方法类型
  4. 编写 HTTP GET 请求的处理程序
  5. 编写 HTTP POST 请求的处理程序
  6. 编写 HTTP PUT 请求的处理程序
  7. 编写 HTTP DELETE 请求的处理程序

1. 使用http模块创建服务器并添加监听器

首先,我们需要创建一个服务器来监听某个特定的端口。这样,如果有任何请求到达该端口,监听器就会被调用。

我们可以使用http模块来实现这一点。

const server = http.createServer(requestListener);  
server.listen(8090);

createServer方法接受监听器作为参数。listen方法接受一个端口号作为参数该端口号将持续监听该端口。

我们来看看空的requestListener方法是什么样子的。

const requestListener = function (req, res) {  
 //all the code goes inside it  
}

2. 对请求进行必要的录入检查

假设我们希望服务器支持 REST API,并且我们希望对请求对象进行以下检查:

  • Content-Type 为 application/json
  • Accept 是 application/json。

我们将使用 req 对象来获取标头详细信息并检查所需的值。

const REQUIRED_CONTENT_TYPE = 'application/json';  
const ACCEPT_ENCODING_1 = 'application/json';  
const ACCEPT_ENCODING_2 = '*/*';

const entryCheck = function (req) {  
  const contentType = req.headers["content-type"];  
  if (!contentType.includes(REQUIRED_CONTENT_TYPE)) {  
    throw new Error("Sorry we only support content type as json format.");  
  }  

  const accept = req.headers["accept"];  
  if (!(accept.includes(ACCEPT_ENCODING_1) ||  
accept.includes(ACCEPT_ENCODING_2))) {  
    throw new Error("Sorry we only support accept json format.");  
  }  
}

让我们来了解一下发生了什么。

  • 首先,我们声明服务器将支持的 content-type 和 accept 标头的常量。
  • Next entryCheck方法用于检查请求头是否包含所需且匹配的详细信息。
  • 如果 Content-type 或 Accept 不匹配,我们将抛出错误。

现在让我们看看如何从类型监听器中调用此方法。

const requestListener = function (req, res) {  
  try {  
    entryCheck(req);  
  } catch (error) {  
    res.writeHead(400);  
    res.end(error.message);  
}
  • writeHead方法接受一个 HTTP 状态码作为参数,可以是任何有效的状态码。它还有一些可选参数,第二个参数是状态消息,第三个参数是请求头。
  • end方法接收将要显示给用户的响应体。执行此方法后,响应将被发送回服务器,整个请求-响应过程即告完成。

注意:我们可以根据条件添加多个条目检查,例如 cookie、主机名/IP 地址、特定标头等。


3.提取请求方法类型

我们需要知道HTTP方法类型,以便分别处理每种方法。

const requestListener = function (req, res) {  
  try {  
    entryCheck(req);  
    const methodType = req.method.toUpperCase();  
    ......

请求对象的 method 属性提供了 Http 方法类型,例如 GET、POST、PUT、DELETE。

接下来,我们可以使用 switch 语句来区别处理不同类型的 HTTP 请求。

....  
switch(methodType){  
  case 'GET':  
    break;  
  case 'POST':  
    break;  
  case 'PUT':  
    break;  
  case 'DELETE':  
    break;  
}

4. 编写 HTTP GET 请求的处理程序

HTTP GET 请求通常用于通过发送唯一详细信息来查找现有对象。

我们可以在每种 Http 方法类型中简单地返回一个通用响应。

case 'GET':  
  res.writeHead(200);  
  res.end(`We received ${methodType} type request`);  
  break;

但是,我们不只是返回简单的响应,而是创建一个对象并对其应用操作。

我们考虑一个包含以下字段的员工对象:

{   
  "_id": "5ec02a534587193b1c607e2c",  
  "name": {  
    "first": "Pace",  
    "last": "Simmons"  
  },  
  "company": "MOLTONIC",  
  "email": "pace.simmons@moltonic.co.uk",  
  "phone": "+1 (941) 562-2930",  
  "address": "274 Dikeman Street, Somerset, Nevada, 6375"  
}

我们将有一个包含上述员工对象数组的对象。

let employeeData = [  
 {   
  "_id": "5ec02a534587193b1c607e2c",  
  "name": {  
    "first": "Pace",  
    "last": "Simmons"  
  },  
  "company": "MOLTONIC",  
  "email": "pace.simmons@moltonic.co.uk",  
  "phone": "+1 (941) 562-2930",  
  "address": "274 Dikeman Street, Somerset, Nevada, 6375"  
 },  
 ......  
]

考虑一个 GET 请求,我们将通过提供_id值来请求特定员工的详细信息

localhost:8090/5ec02a53d8ba79b6992ba757

现在我们需要一个方法,用于在对象数组中查找请求的_id 。我们将编写一个方法,根据_id搜索员工:

let findEmployee = (id) => {  
  return employeeData.find((employee) => {  
    if (employee._id === id)  
      return employee;  
  });  
}

让我们重写 GET HTTP 处理程序代码

const requestListener = function (req, res) {  
  ....  
  case 'GET':  
    getMethodHandler(url, req, res);  
    break;  
  ....  
}

const getMethodHandler = (url, req, res) => {  
  const employeeId = url.substring(1);  
  const employee = findEmployee(employeeId);  
  if (!employee) {  
    res.writeHead(400);  
    res.end(`The employee with id ${employeeId} is not present.`);  
    return;  
  }  
  res.writeHead(200);  
  res.end(JSON.stringify(employee));  
}

我们编写了一个单独的方法

  • 首先,我们找到了请求的_id
  • 我们将该_id传递给findEmployee方法以获取员工对象。
  • 接下来,我们检查是否找到员工对象,如果找不到,则抛出错误。
  • 如果一切顺利,我们会将员工对象返回到响应正文中。

5. 编写 HTTP POST 请求的处理程序

HTTP POST 请求通常用于插入新对象。在本例中,我们将把接收到的员工对象添加到数组中。让我们编写该方法的代码。

let addEmployee = (employee) => {  
  employeeData.push(employee);  
}

接下来,我们需要处理 POST 请求并解析请求体,以获取我们需要插入的员工对象:

const requestListener = function (req, res) {  
  ....  
  case 'POST':  
    getRequestBodyAndGenerateResponse(req, res, postMethodHandler);  
    break;  
  ....  
}

const getRequestBodyAndGenerateResponse = (req, res, callback) => {  
  let body = '';  
  req.on('data', chunk => {  
    body += chunk.toString();  
  });  
  req.on('end', () => {  
    callback(res, JSON.parse(body));  
  });  
}

const postMethodHandler = (res, body) => {  
  try {  
    let reqBody = body;  
    addEmployee(reqBody)  
    res.writeHead(200);  
    res.end(`The Employee object with id is ${reqBody._id} added.`);  
}

让我们来理解一下我们在这里做了什么。

  • 我们定义了一个方法getRequestBodyAndGenerateResponse (req, res, postMethodHandler)。
  • 此方法通过监听“ data ”事件从 req 对象读取数据,并将其附加到一个变量体中。
  • 一旦触发“ end ”事件,表示请求体已完全读取,它将字符串解析为 JSON 并调用传递给它的回调函数。
  • 这个回调函数用于准备响应对象。
  • 在回调函数中,我们首先将员工添加到员工数组中。
  • 然后准备回复并将其发送给用户。

6. 编写 HTTP PUT 请求的处理程序

HTTP PUT 请求通常用于更新旧对象。在本例中,如果数组中存在接收到的员工对象,我们将更新该对象。让我们编写该方法的代码。

let findAndReplace = (employee) => {  
  let employeeFound = findEmployee(employee._id);  
  if (employeeFound) {  
    for (var key in employee) {  
      employeeFound[key] = employee[key];  
    }  
  return true;  
  } else {  
    return false;  
  }  
}

接下来,我们需要处理 PUT 请求并解析请求体,以获取我们需要更新的员工对象:

const requestListener = function (req, res) {  
  ....  
  case 'PUT':  
    getRequestBodyAndGenerateResponse(req, res, putMethodHandler);  
    break;  
  ....  
}

const putMethodHandler = (res, body) => {  
  let reqBody = body;  
  findAndReplace(reqBody);  
  res.writeHead(200);  
  res.end(`The Employee object with id is ${reqBody._id} replaced.`);  
}

让我们来理解一下我们在这里做了什么。

  • 我们定义了一个方法getRequestBodyAndGenerateResponse (req, res, putMethodHandler)。
  • 此方法通过监听“ data ”事件从 req 对象读取数据,并将其附加到一个变量体中。
  • 一旦触发“ end ”事件,表示请求体已完全读取,它将字符串解析为 JSON 并调用传递给它的回调函数。
  • 这个回调函数用于准备响应对象。
  • 在回调函数中,我们首先更新员工数组中接收到的员工对象。
  • 然后准备回复并将其发送给用户。

7. 编写 HTTP DELETE 请求的处理程序

HTTP DELETE 请求通常用于删除现有对象。在本例中,我们将从数组中删除接收到的员工对象_id 。让我们编写该方法的代码。

let deleteEmployee = (id) => {  
  let length = employeeData.length;  
  while (length--) {  
    if (employeeData[length]  
    && employeeData[length]["_id"] === id) {  
      employeeData.splice(length, 1);  
      return true;  
    }  
  }  
  return false;  
}

接下来,我们需要处理 DELETE 请求,获取员工的_id ,并从数组中删除该对象。

const requestListener = function (req, res) {  
  ....  
  case 'PUT':  
    deleteMethodHandler(url, req, res);  
    break;  
  ....  
}

const deleteMethodHandler = (url, req, res) => {  
  const employeeId = url.substring(1);  
  const response = deleteEmployee(employeeId);  
  res.writeHead(200);  
  res.end(`The employee with id ${employeeId} is deleted.`);  
}

让我们来理解一下我们在这里做了什么。

  • 首先,我们找到了请求的_id
  • 我们将该_id传递给deleteEmployee方法以删除员工对象。
  • 如果一切顺利,我们将删除员工对象。
  • 然后准备回复并将其发送给用户。

你可以在这里找到上面的代码。我尝试通过分离数据、方法并使用JS的模块导出/导入功能,将其转换为模块化格式。

如果你喜欢这篇文章,别忘了点赞哦!👏

谢谢!

文章来源:https://dev.to/sachinsarawgi/basic-http-server-using-nodejs-from-scratch-2p6k