零基础之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 相关文章推荐
jQuery EasyUI 的EasyLoader功能介绍
Sep 12 Javascript
Checbox的操作含已选、未选及判断代码
Nov 07 Javascript
JS判断字符串长度的5个方法(区分中文和英文)
Mar 18 Javascript
node.js中的fs.readlinkSync方法使用说明
Dec 17 Javascript
jQuery仿gmail实现fixed布局的方法
May 27 Javascript
EasyUI中在表单提交之前进行验证
Jul 19 Javascript
浅谈JS之iframe中的窗口
Sep 13 Javascript
angular ngClick阻止冒泡使用默认行为的方法
Nov 03 Javascript
基于JS脚本语言的基础语法详解
Jul 22 Javascript
详解微信小程序文件下载--视频和图片
Apr 24 Javascript
vue父子组件的通信方法(实例详解)
Nov 10 Javascript
浅谈vue 锚点指令v-anchor的使用
Nov 13 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
ecshop 批量上传(加入自定义属性)
2012/03/20 PHP
PHP文件大小格式化函数合集
2014/03/10 PHP
Codeigniter实现处理用户登录验证后的URL跳转
2014/06/12 PHP
linux下安装php的memcached客户端
2014/08/03 PHP
Linux php 中文乱码的快速解决方法
2016/05/13 PHP
PHP的PDO大对象(LOBs)
2019/01/27 PHP
js获取当前select 元素值的代码
2010/04/19 Javascript
JavaScript 联动的无限级封装类,数据采用非Ajax方式,随意添加联动
2010/06/29 Javascript
Iframe自适应高度绝对好使的代码 兼容IE,遨游,火狐
2011/01/27 Javascript
JQuery中serialize()用法实例分析
2015/02/06 Javascript
jQuery实现时尚漂亮的弹出式对话框实例
2015/08/07 Javascript
Js获取图片原始宽高的实现代码
2016/05/17 Javascript
谈谈JavaScript中浏览器兼容问题的写法小议
2016/12/17 Javascript
JSON 数据详解及实例代码分析
2017/01/20 Javascript
react.js使用webpack搭配环境的入门教程
2017/08/14 Javascript
vue 实现通过手机发送短信验证码注册功能
2018/04/19 Javascript
Vue+Jwt+SpringBoot+Ldap完成登录认证的示例代码
2018/05/21 Javascript
微信小程序自定义顶部组件customHeader的示例代码
2020/06/03 Javascript
如何实现删除numpy.array中的行或列
2018/05/08 Python
Python 使用类写装饰器的小技巧
2018/09/30 Python
python合并已经存在的sheet数据到新sheet的方法
2018/12/11 Python
Python 实现遥感影像波段组合的示例代码
2019/08/04 Python
python数据类型之间怎么转换技巧分享
2019/08/20 Python
Django 允许局域网中的机器访问你的主机操作
2020/05/13 Python
Python实例方法、类方法、静态方法区别详解
2020/09/05 Python
小结Python的反射机制
2020/09/28 Python
python 爬虫之selenium可视化爬虫的实现
2020/12/04 Python
C和C++经典笔试题附答案解析
2014/08/18 面试题
高等教育专业自荐信范文
2014/03/26 职场文书
学校节能宣传周活动总结
2014/07/09 职场文书
2014年行政人事工作总结
2014/12/09 职场文书
二十年同学聚会致辞
2015/07/28 职场文书
初中教务主任竞聘演讲稿(范文)
2019/08/20 职场文书
python源码剖析之PyObject详解
2021/05/18 Python
一篇文章带你复习java知识点
2021/06/28 Java/Android
Python中第三方库Faker的使用详解
2022/04/02 Python