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

在文件夹下新建两个文件:

  1. .
  2. ├── a.js
  3. └── b.js
  1. function add(a, b) {
  2. return a + b;
  3. }
  4. function mul(a, b) {
  5. return a * b;
  6. }
  7. module.exports = {
  8. add,
  9. mul,
  10. };
  1. const { add, mul } = require("./a");
  2. const sum = add(10, 20);
  3. const result = mul(100, 200);
  4. console.log(sum);
  5. console.log(result);

debugger

新建一个目录,然后初始化npm环境:

  1. npm init -y

会生成一个package.json

  1. {
  2. "name": "debugger-test",
  3. "version": "1.0.0",
  4. "description": "",
  5. "main": "index.js",
  6. "scripts": {
  7. "test": "echo \"Error: no test specified\" && exit 1"
  8. },
  9. "keywords": [],
  10. "author": "",
  11. "license": "ISC"
  12. }

注意里面的"main": "index.js",然后在文件夹里面新建index.js。使用vscode进行调试,main的名字必须和文件夹里面的主文件相同,比如main是app.js,那么调试的文件也应该是app.js。
例如,index.js内容如下:

  1. const http = require("http");
  2. const server = http.createServer((req, res) => {
  3. res.writeHead(200, { "content-type": "text/html" });
  4. res.end("<h1>hello world</h1>");
  5. });
  6. server.listen(3000, () => {
  7. console.log("listening on 3000 port");
  8. });

我们在第四行打一个断点,然后点击运行调试:
image.png
这时我们在浏览器访问3000端口,vscode界面会发生变化:
image.png
浏览器会一直等待加载,然后我们点击下一步,再下一步,返回hello world:
image.png
若继续点下一步,则还会请求一次,这一次是请求favicon。

前端开发和server端开发的区别

image.png
重点不在于语言的学习,而在于思维的转换!

  • 服务稳定性
    • server端可能会遭受各种恶意攻击和误操作
    • 单个客户端可以以为挂掉,但是服务端不能
    • 课程后面会讲解PM2做进程守候
  • 考虑CPU和内存(优化、扩展)
    • 客户端独占一个浏览器,内存和CPU都不是问题
    • server端要承载很多请求,CPU和内存都是稀缺资源
    • 课程后面会讲解使用stream写日志,使用redis存session
  • 日志记录
    • 前端也会参与写日志,但只是日志的发起方,不关心后续
    • server端要记录日志、存储日志、分析日志,前端不关心
    • 课程后面会讲解多种日志记录方式,以及如何分析日志
  • 安全
    • server端要随时准备接收各种恶意攻击,前端则少很多
    • 如:越权操作,数据库攻击等
    • 课程后面会简洁登录验证,预防xss攻击和sql注入
  • 集群和服务拆分
    • 产品发展速度快,流量可能会迅速增加
    • 如何通过扩展机器和服务拆分来承载大流量?
    • 本课程虽然是单机器开发,但是从设计上支持服务拆分

博客项目介绍

  • 目标
    • 开发一个博客系统,具有博客的基本功能
    • 只开发server端,不关心前端
  • 需求
    • 首页,作者主页,博客详情页
    • 登录页
    • 管理中心,新建页,编辑页
  • 技术方案
    • 数据如何存储
      • 博客
        image.png
      • 用户
        image.png
    • 如何与前端对接,即接口设计
      image.png

关于登录:

  • 业界有统一的解决方案,一般不用再重新设计
  • 实现起来比较复杂,课程后面会讲解

Http概述

开发接口(不使用框架)

  • nodejs处理http请求
  • 搭建开发环境
  • 开发接口(暂不连接数据库,暂不考虑登录)

从输入url到显示界面发生了什么?

  • DNS解析,建立TCP连接,发送http请求
  • server接收到http请求,处理,并返回
  • 客户端接收到返回数据,处理数据(如渲染页面,执行js)

例如访问百度:
image.png

点击Header(标头)下的General(常规):
image.png
DNS解析会把https://www.baidu.com/解析为远程地址14.215.177.38:443,443是https的默认端口,http的默认端口是80。
然后看Request Headers(请求标头):
image.png
里面包含一些请求数据。
接着点开Response Headers(响应头):
image.png
里面包含服务端响应的一些数据,具体数据在Response(响应)的body里,点开响应可以看到:
image.png
可以看到是一些html,响应头里的content-type已经规定是text/html
可以在预览看到:
image.png
有一些内容还没有,比如百度的标志,会在下一次请求返回。

nodejs处理http请求

  • get请求和querystring
  • post请求和postdata
  • 路由

简单示例

  1. const http = require('http');
  2. const server = http.createServer((req, res) => {
  3. res.end('hello world');
  4. });
  5. server.listen(8000);
  6. // 然后浏览器访问 http://localhost:8000/

nodejs处理get请求

  • get请求,即客户端要向server端获取数据,如查询博客列表
  • 通过querystring来传递数据,如a.html?a=100&b=200
  • 浏览器直接访问,就发送get请求
  1. const http = require('http');
  2. const querystring = require('querystring');
  3. const server = http.createServer((req, res) => {
  4. console.log(req.method) // GET
  5. const url = req.url // 获取请求的完整url
  6. console.log(url)
  7. req.query = querystring.parse(url.split('?')[1]) // 解析querystring
  8. res.end(JSON.stringify(req.query)) // 将querystring返回
  9. });
  10. 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
  1. const http = require('http')
  2. const server = http.createServer((req, res) => {
  3. if(req.method === 'POST') {
  4. // req数据格式
  5. console.log('req content-type: ', req.headers['content-type'])
  6. // 接收数据
  7. let postData = ''
  8. req.on('data', chunk => {
  9. postData += chunk.toString()
  10. })
  11. req.on('end', () => {
  12. console.log('postData: ', postData)
  13. res.end('hello world!')
  14. })
  15. }
  16. });
  17. server.listen(8000);
  18. console.log("ok");

运行,然后在postman中发送一个post请求:
image.png
这时控制台会输出:

  1. ~/nodejs-post
  2. node app.js
  3. ok
  4. req content-type: application/json
  5. postData: {
  6. "author": "Johe",
  7. "keyword": "java"
  8. }

nodejs处理路由

  1. const http = require('http');
  2. const server = http.createServer((req, res) => {
  3. const url = req.url // 获取请求的完整url
  4. const path = url.split('?')[0]
  5. res.end(path) // 将路由
  6. });
  7. server.listen(8000);

综合

  1. const http = require("http");
  2. const querystring = require("querystring");
  3. const server = http.createServer((req, res) => {
  4. const method = req.method;
  5. const url = req.url;
  6. const path = url.split("?")[0];
  7. const query = querystring.parse(url.split("?")[1]);
  8. // 设置返回格式为JSON
  9. res.setHeader("Content-type", "application/json");
  10. const resData = {
  11. method,
  12. url,
  13. path,
  14. query,
  15. };
  16. // 返回
  17. if (method === "GET") {
  18. res.end(JSON.stringify(resData));
  19. }
  20. if (method === "POST") {
  21. let postData = "";
  22. req.on("data", (chunk) => {
  23. postData += chunk.toString();
  24. });
  25. req.on("end", () => {
  26. res.end(JSON.stringify(postData));
  27. });
  28. }
  29. });
  30. server.listen(8000);