零基础之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 相关文章推荐
一个html5播放视频的video控件只支持android的默认格式mp4和3gp
May 08 Javascript
JavaScript fontsize方法入门实例(按照指定的尺寸来显示字符串)
Oct 17 Javascript
EasyUi datagrid 实现表格分页
Feb 10 Javascript
基于zepto.js实现仿手机QQ空间的大图查看组件ImageView.js详解
Mar 05 Javascript
使用AngularJS处理单选框和复选框的简单方法
Jun 19 Javascript
jquery模拟进度条实现方法
Aug 03 Javascript
JS实现数组简单去重及数组根据对象中的元素去重操作示例
Jan 05 Javascript
浅谈JS对象添加getter与setter的5种方法
Jun 09 Javascript
Puppet的一些技巧
Sep 17 Javascript
微信h5静默和非静默授权获取用户openId的方法和步骤
Jun 08 Javascript
我所理解的JavaScript中的this指向
Sep 04 Javascript
如何利用js在两个html窗口间通信
Apr 27 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/03/04 星际争霸
浅谈PHP语法(1)
2006/10/09 PHP
PHP初学者最感迷茫的问题小结
2010/03/27 PHP
PHP包含文件函数include、include_once、require、require_once区别总结
2014/04/05 PHP
PHP命名空间(Namespace)简明教程
2014/06/11 PHP
叫你如何修改Nginx与PHP的文件上传大小限制
2014/09/10 PHP
关于 Laravel Redis 多个进程同时取队列问题详解
2017/12/25 PHP
php防止表单重复提交实例讲解
2019/02/11 PHP
JS保留两位小数 四舍五入函数的小例子
2013/11/20 Javascript
javascript弹出页面回传值的方法
2015/01/28 Javascript
BootStrap扔进Django里的方法详解
2016/05/13 Javascript
javascript解析ajax返回的xml和json格式数据实例详解
2017/01/05 Javascript
对于Javascript 执行上下文的全面了解
2017/09/05 Javascript
一步步教会你微信小程序的登录鉴权
2018/04/09 Javascript
Vue.js中的组件系统
2019/05/30 Javascript
es6数组的flat(),flatMap()函数用法实例分析
2020/04/18 Javascript
vue项目打包之开发环境和部署环境的实现
2020/04/23 Javascript
vue 解决addRoutes多次添加路由重复的操作
2020/08/04 Javascript
web.py在模板中输出美元符号的方法
2014/08/26 Python
详解Python中的正则表达式
2018/07/08 Python
django写用户登录判定并跳转制定页面的实例
2019/08/21 Python
python Kmeans算法原理深入解析
2019/08/23 Python
Pandas实现dataframe和np.array的相互转换
2019/11/30 Python
PyQt5如何将.ui文件转换为.py文件的实例代码
2020/05/26 Python
解决python调用自己文件函数/执行函数找不到包问题
2020/06/01 Python
解决python3.6用cx_Oracle库连接Oracle的问题
2020/12/07 Python
html5中为audio标签增加停止按钮动作实现方法
2013/01/04 HTML / CSS
生产总经理岗位职责
2013/12/19 职场文书
汉语言文学专业自荐信
2014/06/11 职场文书
大学生求职信例文
2014/06/29 职场文书
竞聘演讲稿怎么写
2014/08/28 职场文书
党员批评与自我批评发言稿
2014/10/14 职场文书
内乡县衙导游词
2015/02/05 职场文书
毕业证明书
2015/06/19 职场文书
2019通用版劳动合同范本!
2019/07/11 职场文书
介绍一下28个JS常用数组方法
2022/05/06 Javascript