零基础之Node.js搭建API服务器的详解


Posted in Javascript onMarch 08, 2019

零基础之Node.js搭建API服务器

这篇文章写给那些Node.js零基础,但希望自己动手实现服务器API的前端开发者,尝试帮大家打开一扇门。

HTTP服务器实现原理

HTTP服务器之所以能提供前端使用的API,其实现原理是服务器保持监听计算机的某个端口(通常是80),等待客户端请求,当请求到达并经过一系列处理后,服务器发送响应数据给到前端。

平时大家通过Ajax调用API,即是发起一次请求,经过服务器处理后,得到结果,然后再进行前端处理。如今使用高级编程语言,要实现服务器那部分功能已经变得非常简单,接下来我们了解一下使用Node.js如何实现。

什么是Node.js?它可以做什么?

Node.js是一个JavaScript的运行时(runtime),它提供了大量用JS与操作系统打交道的API,通过这些API,我们可以调用本地程序、读写磁盘、监听端口、发起网络请求等,这足以开发出一个功能完善的Server。

前期准备

简单介绍完Node.js,开始写代码之前,我们需要安装Node.js,安装详细过程就不说明了,请大家Google或者百度。不同系统安装过程不一样,如果是Linux、Mac,会相对顺利且遇到问题的可能性较低。

判断安装成功与否,windows下,在cmd中执行node -v,Linux、Mac下,在shell中执行node -v,正常输出版本号说明安装成功。

tips:

windows如果提示命令未找到,可能是未配置环境变量

实现简单的Server

Node.js安装成功,我们找个地方新建目录my-server作为我们的存放代码的地方,接下来所有的代码都在该目录下。首先,在my-server的目录下新建文件index.js,用如下代码实现一个简单的Server:

// index.js
// 通过require获取两个node内置模块
const http = require('http');
const nUrl = require('url');
// '127.0.0.1'表明只有本机可访问,'0.0.0.0'表示所有人可访问
const hostname = '127.0.0.1';
const port = 3000;
// 通过http.createServer获取一个server实例
// 其中(req, res) => {},在服务器每次接收到请求时都会被执行
const server = http.createServer((req, res) => {
  let method = req.method; // 客户端请求方法
  let url = nUrl.parse(req.url); // 将请求url字符串转换为node的url对象
  // 如果客户端GET请求'/',会执行这个分支里面的逻辑
  if (method === 'GET' && url.pathname === '/') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello World');
    return;
  }
  // 如果客户端GET请求'/api/user',会执行这个分支里面的逻辑
  if (method === 'GET' && url.pathname === '/api/user') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify({
      code: 0,
      msg: '',
      result: {
        username: 'shasharoman'
      }
    }));
    return;
  }
  // 没有匹配其他分支的话,执行以下逻辑
  res.statusCode = 404;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Not Found');
});
// server开始监听,等待请求到来
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

文件内容编辑保存后,在my-server目录下通过命令node index.js启动服务,然后在浏览器中访问http://127.0.0.1:300/、http://127.0.0.1:300/api/user、http://127.0.0.1:300/xxx观察不同结果。

这是官方Guides经过小小修改得到的代码,添加部分注释以及额外逻辑。主要为了更清晰传达以下几个知识点:

  • 从req对象上获取method与url,这个req对象是客户端请求的“抽象表现”,平时写Ajax指定的绝大部分内容都可以从该对象上获取
  • 中间添加的两个if分支,主要是为了让大家了解服务器如何区分不同请求,决定做不同事情,即路由概念
  • Content-Type: application/json,通常API会使用的响应格式,表明返回数据是json格式,这是一个HTTP头部,属于HTTP协议相关知识
  • statusCode:404,HTTP最常见的错误“Not Found”,也属于HTTP协议相关知识

往前优化一步

通过上面的代码,实现了一个简单Server,但真实场景下我们会这样去实现吗?答案是肯定不会,所以我们还需要一步步完善,做以下几个修改:

  • 增加config,在其中配置hostname,port
  • 增加controller,用于分层以及分模块
  • 增加route,用于定义路由

代码不多,一共五个文件:

  • config.js,配置文件
  • route.js,路由定义文件
  • controller/account.js,账号模块业务实现文件
  • controller/index.js,业务汇总并暴露给外部
  • index.js,项目启动文件
// config.js
exports = module.exports = {
  hostname: '127.0.0.1',
  port: '3000'
};
// route.js
exports = module.exports = [{
  method: 'GET',
  path: '/api/user',
  impl: 'account.userById'
}, {
  method: 'POST',
  path: '/api/user',
  impl: 'account.createUser'
}];
// controller/account.js
exports.userById = userById;
exports.createUser = createUser;
function userById(req, res) {
  res.end('waiting for impl.');
}
function createUser(req, res) {
  res.end('waiting for impl.');
}
// controller/index.js
exports.account = require('./account');
// index.js
const http = require('http');
const nUrl = require('url');
const config = require('./config');
const controller = require('./controller');
const route = require('./route').map(item => {
  console.log(`route ${item.method}:${item.path}`);
  let tuple = item.impl.split('.');
  item.impl = controller[tuple[0]][tuple[1]];
  return item;
});
const server = http.createServer((req, res) => {
  let method = req.method;
  let url = nUrl.parse(req.url);
  let matchRoute = route.find(item => {
    return item.method === method && item.path === url.pathname;
  });
  if (matchRoute) {
    matchRoute.impl(req, res);
    return;
  }
  res.statusCode = 404;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Not Found');
});
server.listen(config.port, config.hostname, () => {
  console.log(`Server running at http://${config.hostname}:${config.port}/`);
});

依旧是用node index.js启动Server,如果要在现有模式下开发一个API,主要就两步:

  • 在route.js中定义路由
  • 在controller/中实现

做这个程度的优化,只是为了向大家传达一些比较宽泛的概念,还不是真正用来写API服务,只是为了大伙练练手。

这个程度还达不到真实场景需求,还需要经过几轮改造,包括模块、层、common、lib、query解析,body解析、更灵活的route等一系列事情,限于篇幅,有机会在一一讲述。

经过我的描述以及代码示例,如果大家有兴趣学习Node.js,建议多搜搜相关知识,保持关注,然后在逐步去熟悉Node.js流行的Web框架如:Express、Koa等,不过框架只是更高层面的封装,基础的概念以及知识还是需要花时间才能掌握。

如果前端想尝试后端编程,请一定先学习HTTP协议,推荐《HTTP权威指南》从头到尾认真看一遍。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

Javascript 相关文章推荐
获取JavaScript用户自定义类的类名称的代码
Mar 08 Javascript
给应用部分的js代码设定一个统一的入口
Jun 15 Javascript
用队列模拟jquery的动画算法实例
Jan 20 Javascript
JavaScript搜索字符串并将搜索结果返回到字符串的方法
Apr 06 Javascript
jquery实现简单实用的打分程序实例
Jul 23 Javascript
jquery实现九宫格大转盘抽奖
Nov 13 Javascript
Javascript随机标签云代码实例
Jun 21 Javascript
vue中for循环更改数据的实例代码(数据变化但页面数据未变)
Sep 15 Javascript
AngularJS中控制器函数的定义与使用方法示例
Oct 10 Javascript
详解vue中使用vue-quill-editor富文本小结(图片上传)
Apr 24 Javascript
jquery+ajax实现异步上传文件显示进度条
Aug 17 jQuery
三步搞定:Vue.js调用Android原生操作
Sep 07 Javascript
详解vue项目中使用token的身份验证的简单实践
Mar 08 #Javascript
Javascript之高级数组API的使用实例
Mar 08 #Javascript
详解基于vue-cli3快速发布一个fullpage组件
Mar 08 #Javascript
JavaScript实现预览本地上传图片功能完整示例
Mar 08 #Javascript
详解JavaScript 的变量
Mar 08 #Javascript
Angular使用ControlValueAccessor创建自定义表单控件
Mar 08 #Javascript
小程序测试后台服务的方法(ngrok)
Mar 08 #Javascript
You might like
php实现的百度搜索某地天气的小偷代码
2014/04/23 PHP
ThinkPHP权限认证Auth实例详解
2014/07/22 PHP
Yii2主题(Theme)用法详解
2016/07/23 PHP
php中钩子(hook)的原理与简单应用demo示例
2019/09/03 PHP
JavaScript加密解密7种方法总结分析
2007/10/07 Javascript
JavaScript入门教程(9) Document文档对象
2009/01/31 Javascript
起点页面传值js,有空研究学习下
2010/01/25 Javascript
JavaScript DOM学习第六章 表单实例
2010/02/19 Javascript
javascript动态加载实现方法一
2012/08/22 Javascript
jquery写个checkbox——类似邮箱全选功能
2013/03/19 Javascript
javascript简单事件处理和with用法介绍
2013/09/16 Javascript
javascript实现的一个随机点名功能
2014/08/26 Javascript
jQuery中parents()和parent()的区别分析
2014/10/28 Javascript
JS实现的网页倒计时数字时钟效果
2015/03/02 Javascript
JavaScript实现为input与textarea自定义hover,focus效果的方法
2015/08/21 Javascript
BootStrap栅格系统、表单样式与按钮样式源码解析
2017/01/20 Javascript
微信小程序选择图片和放大预览图片功能
2017/11/02 Javascript
通过vue提供的keep-alive减少对服务器的请求次数
2018/04/01 Javascript
浅谈webpack+react多页面开发终极架构
2018/11/11 Javascript
Node.js事件的正确使用方法
2019/04/05 Javascript
24个解决实际问题的ES6代码片段(小结)
2020/02/02 Javascript
详细介绍Python中的偏函数
2015/04/27 Python
基于Python 的进程管理工具supervisor使用指南
2016/09/18 Python
Python中的默认参数实例分析
2018/01/29 Python
Pytorch训练过程出现nan的解决方式
2020/01/02 Python
Python 格式化打印json数据方法(展开状态)
2020/02/27 Python
基于python图像处理API的使用示例
2020/04/03 Python
常用的10个Python实用小技巧
2020/08/10 Python
Pandas替换及部分替换(replace)实现流程详解
2020/10/12 Python
Elemental Herbology官网:英国美容品牌
2019/04/27 全球购物
路由表示做什么用的?在linux环境中怎么来配置一条默认路由?
2013/06/07 面试题
工厂门卫岗位职责
2013/11/25 职场文书
幼师求职自荐信范文
2014/01/26 职场文书
护理专业自我鉴定
2014/01/30 职场文书
优秀毕业生自荐信
2014/06/10 职场文书
爱岗敬业事迹材料
2014/12/24 职场文书