ECMAScript
- 定义了语法,写JavaScript和nodejs都必须遵守
- 变量定义,循环、判断、函数
- 原型和原型链,作用域和闭包、异步
- 不能操作DOM,不能监听click事件,不能发送ajax请求
- 不能处理http请求,不能操作文件
- 即,只有ECMAScript,几乎做不了任何实际的项目
具体可参考 ES6 入门教程
JavaScript
- 使用ECMAScript语法规范,外加Web API,缺一不可
- DOM操作,BOM操作,事件绑定,ajax等
- 和ES两者结合,即可完成浏览器端的任何操作
一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系?
要讲清楚这个问题,需要回顾历史。1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给标准化组织 ECMA,希望这种语言能够成为国际标准。次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。
该标准从一开始就是针对 JavaScript 语言制定的,但是之所以不叫 JavaScript,有两个原因。一是商标,Java 是 Sun 公司的商标,根据授权协议,只有 Netscape 公司可以合法地使用 JavaScript 这个名字,且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保证这门语言的开放性和中立性。
因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是可以互换的。
Nodejs
- 使用ECMAScript语法规范,外加Nodejs API,缺一不可
- 处理http,处理文件等,具体参考 Nodejs API文档
- 两者结合,即可完成server端的任何操作
CommenJS
在文件夹下新建两个文件:
.├── a.js└── b.js
function add(a, b) {return a + b;}function mul(a, b) {return a * b;}module.exports = {add,mul,};
const { add, mul } = require("./a");const sum = add(10, 20);const result = mul(100, 200);console.log(sum);console.log(result);
debugger
新建一个目录,然后初始化npm环境:
npm init -y
会生成一个package.json
{"name": "debugger-test","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"}
注意里面的"main": "index.js",然后在文件夹里面新建index.js。使用vscode进行调试,main的名字必须和文件夹里面的主文件相同,比如main是app.js,那么调试的文件也应该是app.js。
例如,index.js内容如下:
const http = require("http");const server = http.createServer((req, res) => {res.writeHead(200, { "content-type": "text/html" });res.end("<h1>hello world</h1>");});server.listen(3000, () => {console.log("listening on 3000 port");});
我们在第四行打一个断点,然后点击运行调试:
这时我们在浏览器访问3000端口,vscode界面会发生变化:
浏览器会一直等待加载,然后我们点击下一步,再下一步,返回hello world:
若继续点下一步,则还会请求一次,这一次是请求favicon。
前端开发和server端开发的区别

重点不在于语言的学习,而在于思维的转换!
- 服务稳定性
- server端可能会遭受各种恶意攻击和误操作
- 单个客户端可以以为挂掉,但是服务端不能
- 课程后面会讲解PM2做进程守候
- 考虑CPU和内存(优化、扩展)
- 客户端独占一个浏览器,内存和CPU都不是问题
- server端要承载很多请求,CPU和内存都是稀缺资源
- 课程后面会讲解使用stream写日志,使用redis存session
- 日志记录
- 前端也会参与写日志,但只是日志的发起方,不关心后续
- server端要记录日志、存储日志、分析日志,前端不关心
- 课程后面会讲解多种日志记录方式,以及如何分析日志
- 安全
- server端要随时准备接收各种恶意攻击,前端则少很多
- 如:越权操作,数据库攻击等
- 课程后面会简洁登录验证,预防xss攻击和sql注入
- 集群和服务拆分
- 产品发展速度快,流量可能会迅速增加
- 如何通过扩展机器和服务拆分来承载大流量?
- 本课程虽然是单机器开发,但是从设计上支持服务拆分
博客项目介绍
- 目标
- 开发一个博客系统,具有博客的基本功能
- 只开发server端,不关心前端
- 需求
- 首页,作者主页,博客详情页
- 登录页
- 管理中心,新建页,编辑页
- 技术方案
- 数据如何存储
- 博客

- 用户

- 博客
- 如何与前端对接,即接口设计

- 数据如何存储
关于登录:
- 业界有统一的解决方案,一般不用再重新设计
- 实现起来比较复杂,课程后面会讲解
Http概述
开发接口(不使用框架)
- nodejs处理http请求
- 搭建开发环境
- 开发接口(暂不连接数据库,暂不考虑登录)
从输入url到显示界面发生了什么?
- DNS解析,建立TCP连接,发送http请求
- server接收到http请求,处理,并返回
- 客户端接收到返回数据,处理数据(如渲染页面,执行js)
例如访问百度:
点击Header(标头)下的General(常规):
DNS解析会把https://www.baidu.com/解析为远程地址14.215.177.38:443,443是https的默认端口,http的默认端口是80。
然后看Request Headers(请求标头):
里面包含一些请求数据。
接着点开Response Headers(响应头):
里面包含服务端响应的一些数据,具体数据在Response(响应)的body里,点开响应可以看到:
可以看到是一些html,响应头里的content-type已经规定是text/html。
可以在预览看到:
有一些内容还没有,比如百度的标志,会在下一次请求返回。
nodejs处理http请求
- get请求和querystring
- post请求和postdata
- 路由
简单示例
const http = require('http');const server = http.createServer((req, res) => {res.end('hello world');});server.listen(8000);// 然后浏览器访问 http://localhost:8000/
nodejs处理get请求
- get请求,即客户端要向server端获取数据,如查询博客列表
- 通过querystring来传递数据,如
a.html?a=100&b=200 - 浏览器直接访问,就发送get请求
const http = require('http');const querystring = require('querystring');const server = http.createServer((req, res) => {console.log(req.method) // GETconst url = req.url // 获取请求的完整urlconsole.log(url)req.query = querystring.parse(url.split('?')[1]) // 解析querystringres.end(JSON.stringify(req.query)) // 将querystring返回});server.listen(8000);
假如访问localhost:8000/api/blog/list?author=zhangsan&keyword=javascript,则console出来的url是/api/blog/list?author=zhangsan&keyword=javascript,最后会返回{"author": "zhangsan", "keyword" :"javascript"}
nodejs处理post请求
- post请求,即客户端要向服务端传递数据,如新建博客
- 浏览器无法直接模拟,需要手写js,或者使用postman
const http = require('http')const server = http.createServer((req, res) => {if(req.method === 'POST') {// req数据格式console.log('req content-type: ', req.headers['content-type'])// 接收数据let postData = ''req.on('data', chunk => {postData += chunk.toString()})req.on('end', () => {console.log('postData: ', postData)res.end('hello world!')})}});server.listen(8000);console.log("ok");
运行,然后在postman中发送一个post请求:
这时控制台会输出:
~/nodejs-post❯ node app.jsokreq content-type: application/jsonpostData: {"author": "Johe","keyword": "java"}
nodejs处理路由
const http = require('http');const server = http.createServer((req, res) => {const url = req.url // 获取请求的完整urlconst path = url.split('?')[0]res.end(path) // 将路由});server.listen(8000);
综合
const http = require("http");const querystring = require("querystring");const server = http.createServer((req, res) => {const method = req.method;const url = req.url;const path = url.split("?")[0];const query = querystring.parse(url.split("?")[1]);// 设置返回格式为JSONres.setHeader("Content-type", "application/json");const resData = {method,url,path,query,};// 返回if (method === "GET") {res.end(JSON.stringify(resData));}if (method === "POST") {let postData = "";req.on("data", (chunk) => {postData += chunk.toString();});req.on("end", () => {res.end(JSON.stringify(postData));});}});server.listen(8000);
