零基础之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 相关文章推荐
Auntion-TableSort国人写的一个javascript表格排序的东西
Nov 12 Javascript
javascript form 验证函数 弹出对话框形式
Jun 23 Javascript
面向对象Javascript核心支持代码分享
May 23 Javascript
Angularjs 滚动加载更多数据
Mar 17 Javascript
深入理解MVC中的时间js格式化
May 19 Javascript
jQuery可见性过滤选择器用法示例
Sep 09 Javascript
使用webpack-dev-server处理跨域请求的方法
Apr 18 Javascript
微信小程序搭建(mpvue+mpvue-weui+fly.js)的详细步骤
Sep 18 Javascript
vue实现中部导航栏布局功能
Jul 30 Javascript
解决node终端下运行js文件不支持ES6语法
Apr 04 Javascript
Object.keys() 和 Object.getOwnPropertyNames() 的区别详解
May 21 Javascript
微信小程序实现自定义底部导航
Nov 18 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
《五等分的花嫁》漫画完结!2020年10月第2期TV动画制作组换血!
2020/03/06 日漫
利用PHP抓取百度阅读的方法示例
2016/12/18 PHP
JavaScript实现禁止后退的方法
2006/12/27 Javascript
WEB页子窗口(showModalDialog和showModelessDialog)使用说明
2009/10/25 Javascript
jQuery ul标签下拉菜单演示代码
2010/12/11 Javascript
基于jquery tab切换(防止页面刷新)
2012/05/23 Javascript
jquery 实现表单验证功能代码(简洁)
2012/07/03 Javascript
jquery聚焦文本框与扩展文本框聚焦方法
2012/10/12 Javascript
jQuery(非HTML5)可编辑表格实现代码
2012/12/11 Javascript
JQuery DataTable删除行后的页面更新利用Ajax解决
2013/05/17 Javascript
使用原生JS实现弹出层特效
2014/12/22 Javascript
jQuery设置指定网页元素宽度和高度的方法
2015/03/25 Javascript
jQuery聚合函数实例
2015/05/21 Javascript
jQuery实现下拉框选择图片功能实例
2015/08/08 Javascript
BootStrap3中模态对话框的使用
2017/01/06 Javascript
JS组件系列之MVVM组件构建自己的Vue组件
2017/04/28 Javascript
AngularJS实现的JSONP跨域访问数据传输功能详解
2017/07/20 Javascript
jquery中done和then的区别(详解)
2017/12/19 jQuery
Vue 源码分析之 Observer实现过程
2018/03/29 Javascript
浅谈Express.js解析Post数据类型的正确姿势
2019/05/30 Javascript
Vue父组件如何获取子组件中的变量
2019/07/24 Javascript
卸载vue2.0并升级vue_cli3.0的实例讲解
2020/02/16 Javascript
[49:20]2014 DOTA2国际邀请赛中国区预选赛5.21 CIS VS TongFu
2014/05/22 DOTA
[51:53]完美世界DOTA2联赛循环赛 LBZS vs DM BO2第二场 11.01
2020/11/02 DOTA
python将视频转换为全字符视频
2019/04/26 Python
Apache,wsgi,django 程序部署配置方法详解
2019/07/01 Python
python 命令行传入参数实现解析
2019/08/30 Python
python 已知三条边求三角形的角度案例
2020/04/12 Python
python+adb+monkey实现Rom稳定性测试详解
2020/04/23 Python
python语音识别指南终极版(有这一篇足矣)
2020/09/09 Python
旧时光糖果:Old Time Candy
2018/02/05 全球购物
金融学专业大学生职业生涯规划
2014/03/07 职场文书
骨干教师培训方案
2014/05/06 职场文书
学校2014重阳节活动策划方案
2014/09/16 职场文书
Typescript类型系统FLOW静态检查基本规范
2022/05/25 Javascript
python计算列表元素与乘积详情
2022/08/05 Python