零基础之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 相关文章推荐
jqeury eval将字符串转换json的方法
Jan 20 Javascript
jQuery判断iframe中元素是否存在的方法
May 11 Javascript
JavaScript动态插入script的基本思路及实现函数
Nov 11 Javascript
学习使用grunt来打包JavaScript和CSS程序的教程
Jan 04 Javascript
Bootstrap自动适应PC、平板、手机的Bootstrap栅格系统
May 27 Javascript
jquery dataTable 后台加载数据并分页实例代码
Jun 07 jQuery
使用JavaScript实现一个小程序之99乘法表
Sep 21 Javascript
EasyUI框架 使用Ajax提交注册信息的实现代码
Sep 27 Javascript
微信小程序之数据缓存的实例详解
Sep 29 Javascript
JS使用Dijkstra算法求解最短路径
Jan 17 Javascript
适合后台管理系统开发的12个前端框架(小结)
Jun 29 Javascript
使用Cargo工具高效创建Rust项目
Aug 14 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数据库调用类调用实例(详细注释)
2012/07/12 PHP
PHP环境中Memcache的安装和使用
2015/11/05 PHP
PHP实现自动识别原编码并对字符串进行编码转换的方法
2016/07/13 PHP
PHP如何获取Cookie并实现模拟登录
2020/07/16 PHP
javascript+dom树型菜单类,希望朋友们一起进步
2007/05/03 Javascript
javascript中数组的多种定义方法和常用函数简介
2014/05/09 Javascript
javascript数组操作方法小结和3个属性详细介绍
2014/07/05 Javascript
jQuery中ajax和post处理json的不同示例对比
2014/11/02 Javascript
avalon js实现仿google plus图片多张拖动排序附源码下载
2015/09/24 Javascript
JavaScript隐式类型转换
2016/03/15 Javascript
JS递归遍历对象获得Value值方法技巧
2016/06/14 Javascript
Actionscript与javascript交互实例程序(修改)
2016/09/22 Javascript
js对字符串进行编码的方法总结(推荐)
2016/11/10 Javascript
a标签置灰不可点击的实现方法
2017/02/06 Javascript
javascript自执行函数
2017/02/10 Javascript
从零开始做一个pagination分页组件
2017/03/15 Javascript
jQuery实现拼图小游戏(实例讲解)
2017/07/24 jQuery
vue单页应用中如何使用jquery的方法示例
2017/07/27 jQuery
Vue配置marked链接添加target="_blank"的方法
2019/07/19 Javascript
JQuery中DOM节点的操作与访问方法实例分析
2019/12/23 jQuery
通过实例解析chrome如何在mac环境中安装vue-devtools插件
2020/07/10 Javascript
vue 图片裁剪上传组件的实现
2020/11/12 Javascript
[03:01]2014DOTA2国际邀请赛 小组赛7月13日TOPPLAY
2014/07/14 DOTA
使用Python下的XSLT API进行web开发的简单教程
2015/04/15 Python
不同版本中Python matplotlib.pyplot.draw()界面绘制异常问题的解决
2017/09/24 Python
浅析Python 3 字符串中的 STR 和 Bytes 有什么区别
2018/10/14 Python
在python 中实现运行多条shell命令
2019/01/07 Python
Python实战购物车项目的实现参考
2019/02/20 Python
浅谈Python __init__.py的作用
2020/10/28 Python
会计专业的自荐信
2013/12/12 职场文书
学校安全责任书
2014/04/14 职场文书
销售行政专员岗位职责
2014/06/10 职场文书
父亲节活动策划方案
2014/08/24 职场文书
客房部经理岗位职责
2015/02/02 职场文书
楚门的世界观后感
2015/06/03 职场文书
投诉信格式范文
2015/07/02 职场文书