返回顶部
首页 > 资讯 > 服务器 >NodeJS基础API搭建服务器的示例分析
  • 371
分享到

NodeJS基础API搭建服务器的示例分析

2024-04-02 19:04:59 371人浏览 安东尼
摘要

这篇文章主要介绍了nodejs基础api搭建服务器的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。项目介绍有一个简单的食品店网站,它

这篇文章主要介绍了nodejs基础api搭建服务器的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

项目介绍

有一个简单的食品店网站,它包括一个主页index和一个详情页detail。主页展示食品店的所有食品,包括食品图片、名称、价格3个信息,如下图所示。

NodeJS基础API搭建服务器的示例分析

用户点击任何一项食品就会跳转到对应的详情页,包括食品图片、名称、价格和描述4个信息,如下图所示。

NodeJS基础API搭建服务器的示例分析

项目结构

项目的文件结构如下所示。

node-example
 |--data(存放项目数据的文件夹)
   |--detail.JSON(存放食品详情数据)
   |--foods.json(存放首页食品数据)
 |--model(提供访问和操作数据服务的数据模型)
   |--detail.js(详情数据访问模块)
   |--foods.js(食品数据访问模块)
 |--public(存放CSS,js,图片等静态文件)
   |--css(存放css文件的文件夹)
   |--img(存放图片的文件夹)
   |--js(存放js文件的文件夹)
 |--route(路由,控制器)
   |--api(处理普通请求的路由,或者叫控制器)
   |--static(处理静态文件请求的路由,或者叫控制器)
 |--views(视图,即用户界面)
   |--index.html(主页界面)
   |--detail.html(详情页面)
 |--server.js(服务器启动文件)
 |--package.json(项目包信息)
 |--README.md(项目信息以及启动方法描述)

本文只讲解服务端编程,因此两个简单界面的实现过程这里就不再啰嗦了。假设你已经能够自行完成前端的界面编程,下面开始讲解服务端编程。

编写服务器

server.js中要完成服务器的创建和启动,并将请求转发给相应的路由去处理。详细代码如下所示(假设我们已经有了能够正常工作的路由,这里采用Top-Down的思路,我们一层一层地往下写,专注于解决每个层次的问题)。代码中使用正则表达式来判定客户端request是否是在请求静态文件,如果是,则交给专门处理静态文件请求的路由static去处理,否则交给普通请求的路由器api去处理。普通请求根据它的Http方法来判断使用get或者post。最后,设置服务器监听3000端口,server.js的代码就算完成了。

var http = require('http');
var url = require('url');
var api = require('./route/api');
var static = require('./route/static');

// 匹配静态文件夹路径的正则表达式,用于判定请求是否为静态文件请求
var staticExp = /\/public\/(img|css|js)\/[a-z]*\.(jpg|png|gif|css|js)/;

http.createServer((req, res) => {
 var pathname = url.parse(req.url).pathname;
 if (staticExp.test(pathname)) {// 静态文件请求交由static处理
 static.get(__dirname + pathname, res);
 } else if (req.method == 'POST') {// 处理普通post请求
 api.post(req, res);
 } else {// 处理普通get请求
 api.get(req, res);
 }
}).listen(3000);
console.log('[Server Info] Start server at http://localhost:3000/');

编写路由

我从简单的开始,先写处理静态文件请求的路由static。这个路由的逻辑很简单,只要客户端想要请求某个静态文件(css/js/图片),就将被请求的文件发送给客户端即可。代码如下所示。有以下几点需要注意的地方,首先,客户端请求文件,需要判断文件是否存在,如果存在才将其发送给客户端,不存在则作其他处理(这里我暂时没做其他处理)。其次,将文件响应给客户端的时候,需要设置好http报头的MIME type,这样文件发过去之后客户端才能识别出文件类型从而正确使用。最后,像图片、音频等多媒体文件需要用二进制的读写方式,所以在响应图片的时候记得加上“binary”。

var fs = require('fs');
var path = require('path');

var MIME = {};
MIME[".css"] = "text/css";
MIME[".js"] = "text/js";
MIME[".jpg"] = "image/jpeg";
MIME[".jpeg"] = "image/jpeg";
MIME[".png"] = "image/png";
MIME[".gif"] = "image/gif";

function get(pathname, res) {
 if (fs.existsSync(pathname)) {
 var extname = path.extname(pathname);
 res.writeHead(200, {'Content-Type': MIME[extname]});
 fs.readFile(pathname, (err, data) => {
  if (err) {
  console.log(err);
  res.end();
  } else {
  if (isImage(extname)) {
   res.end(data, "binary");// 二进制文件需要加上binary
  } else {
   res.end(data.toString());
  }
  }
 });
 }
}

// 根据拓展名判断是否为图片
function isImage(extname) {
 if (extname === '.jpg' || extname === '.jpeg' ||
 extname === '.png' || extname === '.gif') {
 return true;
 }
 return false;
}
// 提供给其他模块使用的接口
module.exports = {
 get: get
};

static写完了,下面来继续写api。api需要根据请求的URL来响应对应的内容。例如客户端请求“/”,就响应它网站的主页,请求“/detail?id=0”就响应它id为0的食品的详情页面。如果客户端请求了不存在的URL,则给回一个404响应,表示没有找到。代码如下所示。这里我分了两个handler,本项目没有post操作,所以只有getHandler会使用到。给出postHanlder的目的是为了简单说明如何写处理客户端post请求的路由。

以getHanlder[‘/']为例,当客户端请求“/”的时候,不是简单地把index.html响应给服务器这么简单,想象一下,一家食品店,每天提供的菜式可能会有所不同,或者因为季节问题而导致每个季节的特色菜都有所不同,所以我们网站主页展示的菜式也可能随之而变化。因此,我们需要根据数据库中存储的主页数据来动态渲染主页的内容。我把idnex.html写成模板,为了不适用jade等模板引擎,我在html里面使用如同“{{foodMenu}}”这种形式的标记,当读取完模板之后,利用简单的字符串操作将标记替换成我们需要动态渲染的内容,即可实现动态渲染HTML的目的。

静态文件之外的其他路由,或者叫控制器(controller),一般都会包含业务逻辑,即业务逻辑一般是在这一层完成的。像上面的根据数据库内容动态渲染出首页,或者你在其他场景下面会见到的如登录注册的数据检验,成功登录之后将客户端重定向到对应的用户界面等等业务逻辑都是在这一层实现。

var fs = require('fs');
var url = require('url');
var querystring = require('querystring');
var foods = require('../model/foods')();
var detail = require('../model/detail')();

var getHandler = {};
var postHandler = {};

// 处理对主页的请求
getHandler['/'] = function(req, res) {
 var foodMenu = "";
 // 拼装首页数据
 var food = foods.getAllFoods();
 for (var i = 0; i < food.length; ++i) {
  foodMenu += '<div class="food-card" id="' + food[i].id + '"><img src="';
  foodMenu += food[i].image + '"><h2>' + food[i].name + '</h2><h3>' + food[i].price + '</h3></div>';
 }

 res.writeHead(200, {"Content-Type": "text/html"});
 fs.readFile(__dirname + '/../views/index.html', (err, data) => {
 if (err) {
  console.log(err);
  res.end();
 } else {
  // 动态渲染模板
  res.end(data.toString().replace('{{foodMenu}}', foodMenu));
 }
 });
};

// 处理对详情页面的请求
getHandler['/detail'] = function(req, res) {
 var query = querystring.parse(url.parse(req.url).query);
 var foodDetail = detail.getDetail(query.id);
 res.writeHead(200, {"Content-Type": "text/html"});
 fs.readFile(__dirname + '/../views/detail.html', (err, data) => {
 // 动态渲染模板
 res.end(data.toString().replace('{{image}}', foodDetail.image)
  .replace('{{name}}', foodDetail.name)
  .replace('{{description}}', foodDetail.description)
  .replace('{{price}}', foodDetail.price));
 });
};

// 404响应,告知客户端资源未找到
getHandler['/404'] = function(req, res) {
 res.writeHead(404, {"Content-Type": "text/plain"});
 res.end("404 Not Found");
};

// post请求的处理方法示例
postHandler['/'] = function(res, data) {
 // do something
};

// get请求
function get(req, res) {
 var reqUrl = url.parse(req.url);
 if (typeof getHandler[reqUrl.pathname] === "function") {
 getHandler[reqUrl.pathname](req, res);
 } else {
 getHandler["/404"](req, res);
 }
}

// post请求(示例)
function post(req, res) {
 var reqUrl = url.parse(req.url);
 if (typeof postHandler[reqUrl.pathname] === "function") {
 var postData = "";
 req.on('data', (data) => {
  postData += data;
 });
 req.on('end', () => {
  postData = querystring.parse(postData);
  postHandler[reqUrl.pathname](res, postData);
 });
 } else {
 getHandler["/404"](req, res);
 }
}

// 提供给其他模块使用的接口
module.exports = {
 get: get,
 post: post
};

最后,讲一下post方法的处理过程,虽然本项目中没有使用到post。post方法跟get方法最主要的不同之处在于post方法除了发送http头部信息之外还带有客户端提交的数据。在接收到post请求的时候,需要将数据读取出来,读取数据的方式也挺简单,只要给request设置监听器就行了。当request对象收到数据的时候会触发“data”事件,因此,给这个事件设置监听器,让它收到数据的时候就把数据保存起来。在接收完一个请求全部的post数据之后会触发“end”事件,因此,给这个事件设置监听器,使得在接收完全部数据之后才开始对提交的数据进行相关的操作。

编写数据模型

先拿主页来讲吧。通过前面的截图,我们可以知道,主页上的数据包括展示菜品的图片、名称、价格,另外需要根据不同的菜品跳转到对应的详情页,因此还需要一个id来用作标识符。最后,可以得到如下的数据模型(下面的模型我使用json描述,你也可以采取其他办法)。这个数据模型描述了主页的数据模型,即首页有很多个食品foods,用数组表示,每个数据元素代表一个食品。每个食品包括四项信息,id,image,name,price。id的值是一个数字,作为唯一标识符。image是一个字符串,用来指明图片地址。name的值是字符串,表示食品的名字,price的值是一个字符串,表示食品的价格。

{
 "foods": [{
 "id": "number",
 "image": "string",
 "name": "string",
 "price": "string"
 }]
}

设计好数据模型的目的是方便我们设计伪数据,也方便我们对数据进行操作,一般在开始编程之前要做的事情就是设计好数据模型(数据结构),这样写程序时候才会更加顺利,很多接口才能规范下来。虽然我这里把model这一步放在了最后,但我这里model里面只是写了数据访问模块,不代表数据模型是最后才设计的,只是因为我这里讲解的思路是自定向下,刚好讲到model就顺带提一提数据模型设计。

下面以foods.js为例来讲解如何编写model。代码如下所示。这里由于没有数据库(涉及数据库的话对于新手来说比较麻烦,为了讲清楚过程本文将不采用数据库存储数据),我将所有数据使用json文件存储,例如foods.json中存储了主页的所有食品的数据。foods model将对外提供接口,用于支持访问主页的食品数据,修改食品数据等操作(数据库常说的增删查改CRUD四个操作)。本项目只需要用到查询所有视频的操作,所以我这里简单实现了一个获取所有食品的方法,另外附带一个根据id获取单个食品的方法(这个方法仅是示例,没有用到)。

var fs = require('fs');

module.exports = function() {
 // 读取文件中的数据,将其转成一个对象方便使用
 var data = JSON.parse(fs.readFileSync(__dirname + '/../data/foods.json'));
 var foods = {
 getAllFoods: getAllFoods,
 getFood: getFood
 };

 // 获取所有食品
 function getAllFoods() {
 return data.foods;
 }

 // 根据id获取单个食品
 function getFood(id) {
 for (var i = 0; i < data.foods.length; ++i) {
  if (data.foods[i].id == id)
  return data.foods[i];
 }
 }

 return foods;
};

model里面的模块一般提供数据操作的服务供控制器使用,所以在这一层就主要关注实现数据CRUD操作即可,基本没有什么业务逻辑了。

照着写foods的思路,我们再把detail写完,整个项目就完成了。是不是挺简单的。进到项目目录下面,使用node server.js启动服务器跑一跑吧。

NodeJS基础API搭建服务器的示例分析

最后,看完整个项目,你大概可以发现整个编写过程,或者说每个模块的划分,都好像遵照某种特定的模式在进行,其实我是按照mvc的模式来编写这个项目的,最近在另外一门学课的学习中也经常用到MVC,觉得还是挺不错的一种设计模式,有兴趣可以研究一下。当然,我不能说我写的代码完全符合MVC的规范,毕竟每个人的理解都可能有那么一些出入。本文仅供参考,欢迎交流建议,谢谢!

感谢你能够认真阅读完这篇文章,希望小编分享的“NodeJS基础API搭建服务器的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网服务器频道,更多相关知识等着你来学习!

--结束END--

本文标题: NodeJS基础API搭建服务器的示例分析

本文链接: https://lsjlt.com/news/73072.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • NodeJS基础API搭建服务器的示例分析
    这篇文章主要介绍了NodeJS基础API搭建服务器的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。项目介绍有一个简单的食品店网站,它...
    99+
    2024-04-02
  • NodeJS基础API搭建服务器详细过程记录
    前言 在习惯了使用express框架,jade模板引擎等现成工具来写代码之后,很多人对于基本的NodeJS API会慢慢生疏。本文将以一个超小型web项目,来详细介绍如何使用NodeJS基础的http, f...
    99+
    2022-06-04
    过程 服务器 基础
  • nodejs基础之多进程的示例分析
    小编给大家分享一下nodejs基础之多进程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!具体如下:Node.js 多进...
    99+
    2024-04-02
  • CentOS7服务器搭建的示例分析
    这篇文章主要介绍了CentOS7服务器搭建的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。作为服务器Linux系统比Windows系统有更高的稳定性、更好的性能、占用...
    99+
    2023-06-26
  • Linux搭建svn服务器的示例分析
    今天给大家介绍一下Linux搭建svn服务器的示例分析。文章的内容小编觉得不错,现在给大家分享一下,觉得有需要的朋友可以了解一下,希望对大家有所帮助,下面跟着小编的思路一起来阅读吧。SVN是一个开放源代码的控制系统,通过采用分支管理系统的管...
    99+
    2023-06-28
  • MySQL基础的示例分析
    这篇文章给大家分享的是有关MySQL基础的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。MySQL入门mySQL (关系型数据库管理系统)MySQL是一个关系型数据库管理...
    99+
    2024-04-02
  • javaScript基础的示例分析
    这篇文章主要为大家展示了“javaScript基础的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“javaScript基础的示例分析”这篇文章吧。首先讲...
    99+
    2024-04-02
  • Three.js基础的示例分析
    这篇文章给大家分享的是有关Three.js基础的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、Three.js官网及使用Three.js必备的三个条件1.Three....
    99+
    2024-04-02
  • node.js基础的示例分析
    这篇文章给大家分享的是有关node.js基础的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是NodeJSJS是脚本语言,脚本语言都需要一个解析器才能运行。对于写在H...
    99+
    2024-04-02
  • Java基础的示例分析
    小编给大家分享一下Java基础的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、Java主要特点简单性、跨平台性、分布性、安全性、健壮性、平台独立与可移...
    99+
    2023-06-20
  • redis基础配置的示例分析
    这篇文章将为大家详细讲解有关redis基础配置的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Redis的ms主从集群作用:1、主从备份防止宕机2、读写分离,分担...
    99+
    2024-04-02
  • AngularJS基础知识的示例分析
    这篇文章主要介绍了AngularJS基础知识的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。指令AngularJS 指令是扩展的 H...
    99+
    2024-04-02
  • shell基础语法的示例分析
    这篇文章将为大家详细讲解有关shell基础语法的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。不论前端还是后端,再学会Linux的基础上,还应该学会写一些简单的Shell。不止是工作,日常中想做一...
    99+
    2023-06-09
  • oracle基础语法的示例分析
    这篇文章主要介绍了oracle基础语法的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Oracle数据库的初步学习数据库的安装及其配置,使用默认选项进行安装即可ora...
    99+
    2023-06-15
  • Java基础之Maven的示例分析
    这篇文章将为大家详细讲解有关Java基础之Maven的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、Maven是什么?Maven是一个跨平台的项目管理工具。作为Apache组织的一个颇为成功的...
    99+
    2023-06-15
  • java基础之this的示例分析
    小编给大家分享一下java基础之this的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1、this关键字首先需要提醒的是,在整个Java之中,this是...
    99+
    2023-06-20
  • Ruby基础代码的示例分析
    Ruby基础代码的示例分析,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Ruby语言的学习和其他编程语言一样,首先要从基础开始。在这里我们为大家介绍了一下Ruby基础代码中...
    99+
    2023-06-17
  • java数组基础的示例分析
    这篇文章主要介绍java数组基础的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!数组数组(Array):相同类型数据的集合。Java 数组初始化的两种方法: 静态初始化: 程序员在初始化数组时为数组每个元素赋...
    99+
    2023-05-30
    java 数组
  • springboot-curd基于mybatis项目搭建的示例分析
    springboot-curd基于mybatis项目搭建的示例分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。项目结构:pom.xml文件:   ...
    99+
    2023-06-28
  • mysql中基础知识的示例分析
    这篇文章将为大家详细讲解有关mysql中基础知识的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。mysql架构一、网络连接层客户端连接器(Client Conne...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作