零基础之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 相关文章推荐
cnblogs中在闪存中屏蔽某人的实现代码
Nov 14 Javascript
围观tangram js库
Dec 28 Javascript
JQuery.Ajax之错误调试帮助信息介绍
Jul 04 Javascript
探讨在JQuery和Js中,如何让ajax执行完后再继续往下执行
Jul 09 Javascript
利用JavaScript实现新闻滚动效果(实例代码)
Nov 27 Javascript
javascript实现瀑布流加载图片原理
Feb 02 Javascript
vue.js的提示组件
Mar 02 Javascript
详解vue服务端渲染(SSR)初探
Jun 19 Javascript
jQuery制作全屏宽度固定高度轮播图(实例讲解)
Jul 08 jQuery
JS实现盒子跟着鼠标移动及键盘方向键控制盒子移动效果示例
Jan 29 Javascript
小程序实现短信登录倒计时
Jul 12 Javascript
React中获取数据的3种方法及优缺点
Feb 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
php 文件缓存函数
2011/10/08 PHP
PHP实现的下载远程图片自定义函数分享
2015/01/28 PHP
php使用json_decode后数字对象转换成了科学计数法的解决方法
2017/02/20 PHP
PHP+百度AI OCR文字识别实现了图片的文字识别功能
2019/05/08 PHP
Laravel修改验证提示信息为中文的示例
2019/10/23 PHP
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
2013/11/06 Javascript
将中国标准时间转换成标准格式的代码
2014/03/20 Javascript
javascript设置连续两次点击按钮时间间隔的方法
2014/10/28 Javascript
深入探寻seajs的模块化与加载方式
2015/04/14 Javascript
JS实现简单的二维矩阵乘积运算
2016/01/26 Javascript
使用JS实现图片展示瀑布流效果的实例代码
2016/09/12 Javascript
URL的参数中有加号传值变为空格的问题(URL特殊字符)
2016/11/04 Javascript
React创建组件的三种方式及其区别
2017/01/12 Javascript
详解angularJs中自定义directive的数据交互
2017/01/13 Javascript
vue上传图片组件编写代码
2017/07/26 Javascript
利用Node.js检测端口是否被占用的方法
2017/12/07 Javascript
原生JS forEach()和map()遍历的区别、兼容写法及jQuery $.each、$.map遍历操作
2019/02/27 jQuery
JS面向对象之多选框实现
2020/01/17 Javascript
[00:57]林俊杰助阵DOTA2亚洲邀请赛
2015/01/28 DOTA
Python遍历文件夹和读写文件的实现代码
2016/08/28 Python
python常用函数详解
2016/09/13 Python
Python批量提取PDF文件中文本的脚本
2018/03/14 Python
selenium+python实现自动登录脚本
2018/04/22 Python
python 把文件中的每一行以数组的元素放入数组中的方法
2018/04/29 Python
python [:3] 实现提取数组中的数
2019/11/27 Python
使用keras实现densenet和Xception的模型融合
2020/05/23 Python
python中对二维列表中一维列表的调用方法
2020/06/07 Python
python 利用matplotlib在3D空间绘制二次抛物面的案例
2021/02/06 Python
css3实现3D色子翻转特效
2014/12/23 HTML / CSS
世界上最大的街头服饰网站:Karmaloop
2017/02/04 全球购物
英国花园药房: The Garden Pharmacy
2017/12/28 全球购物
Urban Outfitters德国官网:美国跨国生活方式零售公司
2018/05/21 全球购物
俄罗斯苹果优质经销商商店:iPort
2020/05/27 全球购物
社区务虚会发言材料
2014/10/20 职场文书
社区党员群众路线教育实践活动心得体会
2014/11/03 职场文书
2014员工聘用协议书(最新版)
2014/11/24 职场文书