20210902#_nodejs-day02

上一级: 20210816# 【黑马前端】

目录

01-授课思路

反馈

  • 一整天感觉老师讲了特别多知识,没有重点的感觉。听着听着就走神了。晚上写代码的时候发现都不会写。。。。

    • fs 模块读写文件
    • http 模块创建 web服务
  • 第一天上午概念性东西还好,到了下午有点蒙圈了。自己没有跟上,而且提问好吓人。不过毕竟是总监,我还是匿了。请不要给我穿小鞋 。 谢谢!!!!!

  • 讲的特别好,通俗易懂!有个小建议,在讲到新知识点的时候,给我们解释完之后留几秒钟的时间让我们思考一下。

  • 讲的很棒,有个问题不清楚。server.on('request', function (req, res) 监听的是这个 request事件吗? 当时这个单词写错了不能运行,但是后面简写的时候又可以省略,希望虎哥在简单讲下这块?

  • fs.writeFile写入数据,文件内本身已经有内容了,再写入会覆盖文件里面的内容,若是不想被覆盖要怎么解决呢?

  • 虎哥,当我们使用writeFile()方法的时候,是不是会覆盖?就是如果原来的文件里有文字,用这个方法写入的文字会把原来的文字给盖掉,有啥解决方法么?除了用appendFile()这种方法,有没有可以仍然使用writeFile()就可以解决覆盖的问题的?

  • 老师的ppt做的挺好的

  • 讲的太快了,跟不上节奏,希望讲慢点,谢谢

  • 虎哥语速慢点

  • 老师辛苦了。视频声音有点小,另外有两个问题:1.怎样在一个文件夹下面访问别的文件夹的文件,复制路径放在后面不行。2.var http=require('http'); var server=http.createServer(function(req,res){ console.log('有人访问了。'); res.setHeader('Content-type','text/html;charset=utf-8'); res.write('哈哈哈

    hello

    '); res.end(); }) server.listen(9000,function(){ console.log('please visit: http://localhost:9000'); }) 为什么“有人访问了”出现了两次?

  • 对于安装多版本node的作用,以及如何使用nvm管理不太清楚,希望老师能再讲解下

  • 老师讲课棒棒哒!!!

  • 老师辛苦了,

  • 多加练习

  • 有点小快····

  • 多敲多练

  • 忙了一晚上,白天装了个nodejs 6.11.3,晚上什么都用不了了,麻烦老师再给我们讲解下有关知识

  • 第一次接触,还是有点不熟悉,需要花时间去消化。老师辛苦了!!!

复习

了解:

  1. 浏览器渲染引擎工作原理
  2. 浏览器访问网站过程
  3. Web开发本质:请求、处理、响应
  • C/S 架构 和 B/S 架构
  1. node.js 是什么?
  2. node.js 有什么特点?
  3. node.js 安装
  4. node.js 开发网站 和 传统方式开发网站(PHP、JSP等)有什么区别?
  5. node.js REPL
  • 如何进入 REPL 环境
  • 如何退出 REPL 环境
  1. 通过创建 js 文件开发 node.js 程序

重点:

  1. 通过 fs 模块实现文件读写操作
  2. path 模块使用
  3. __dirname__filename
  4. node.js 中异步是如何实现的?为什么说 node.js 即是单线程又是异步非阻塞 I/O 模型?
  • 调用栈
  • 调用队列
  1. 编写简单的 http 服务程序,无论请求当前网站下哪个路径,都返回 hello world
  • 乱码问题。res.setHeader('Content-Type', 'text/plain; charset=utf-8');
  • 设置显示 HTML 内容。res.setHeader('Content-Type', 'text/html; charset=utf-8');

补充:

1. 文件操作时,无需先判断文件是否存在,直接操作即可,如果文件不存在会反应在 error 对象中
2. try-catch 的使用

今日授课内容

  1. 通过 node.js 编写 http 服务程序 - 通过读取静态 HTML 文件来响应用户请求(带图片和外部CSS样式)

  2. 通过 node.js 编写 http 服务程序 - 模拟 Apache 服务器处理静态资源

  • mime 第三方模块使用
  1. 在请求服务器的时候,请求的 url 就是一个标识!

  2. request(http.IncomingMessage) 和 response(ServerResponse) 对象介绍

  • request: 服务器解析用户提交的 http 请求报文,将结果解析到 request 对象中。凡是要获取和用户请求相关的数据都可以通过 request 对象获取
  • response: 在服务器端用来向用户做出响应的对象。凡是需要向用户(客户端)响应的操作,都需要通过 response 对象来进行。
  1. NPM

  2. package.json、package-lock.json 文件介绍

  • 元数据
  1. 自己设计路由,实现 HackerNews网站部分功能
  • underscore 模块介绍、url 模块介绍
  1. 在html页面中写相对路径'./' 和 绝对路径 '/'的含义
  • 此处 ./ 相对的是吐出当前页面的url
  1. 通过设置 http 响应报文头实现弹框下载功能
  • 设置 Content-Type: application/octet-stream
  • 设置 Content-Disposition: attachment; filename=demo.txt

其他参考

request 对象 和 response对象

request 对象

  • request 对象类型 <http.IncomingMessage>, 继承自stream.Readable
  • request 对象常用成员
    • request.headers
    • request.rawHeaders
    • request.httpVersion
    • request.method
    • request.url

response 对象

  • response 对象类型 <http.ServerResponse>

  • response 对象常用成员

    • response.writeHead(statusCode[, statusMessage][, headers])

      1. This method must only be called once on a message and it must be called before response.end() is called.
      • 这个方法在每次请求响应前都必须被调用(只能调用一次)。并且必须在end()方法调用前调用
      1. If you call response.write() or response.end() before calling this, the implicit/mutable headers will be calculated and call this function for you.
      • 如果在调用writeHead()方法之前调用了write() 或 end()方法,系统会自动帮你调用writeHead()方法,并且会生成默认的响应头
      1. When headers have been set with response.setHeader(), they will be merged with any headers passed to response.writeHead(), with the headers passed to response.writeHead() given precedence.
      • 如果通过 res.setHeader() 也设置了响应头,那么系统会将serHeader()设置的响应头和writeHead()设置的响应头合并。 并且writeHead()的设置优先
// 示例代码:
res.writeHead(200, 'OK', {
  'Content-Type': 'text/html; charset=utf-8',
  'Content-Length': Buffer.byteLength(msg)
});
  • response.write(chunk[, encoding][, callback])

    • 参数1:要写入的数据,可以是字符串或二进制数据,必填
    • 参数2:编码,默认是utf8,选填。
    • 参数3:回调函数,选填。
  • response.end([data][, encoding][, callback])

    • 结束响应。
    • This method signals to the server that all of the response headers and body have been sent; that server should consider this message complete. The method, response.end(), MUST be called on each response.
    • res.end()这个方法告诉服务器所有要发送的响应头和响应体都发送完毕了。可以人为这次响应结束了。
    • 同时每次响应都必须调用该方法,用来结束响应
    • 参数1:结束响应前要发送的数据,选填。
    • 参数2:编码,选填。
    • 参数3:回调函数,选填。
  • response.setHeader(name, value)

    • 设置响应报文头
  • response.statusCode

    • 设置或读取http响应码
  • response.statusMessage

    • 设置或读取http响应状态消息

NPM - Node Package Manager - Node 包管理器

NPM 是什么?

  • npm(全称Node Package Manager,即node包管理器)是Node.js默认的、以JavaScript编写的软件包管理系统。
  • npm 官方网站
  • npm 官方文档

一般当我们说npm的时候可能指3件事

  1. NPM 网站:https://www.npmjs.com/
  2. NPM 包管理库,存储了大量的JavaScript代码库
  3. NPM 客户端,我们所使用的npm命令行工具。使用JavaScript开发的基于node.js的命令行工具,本身也是Node的一个包。

参考图片

NPM

NPM

NPM 官方解释:

  • npm is the package manager for JavaScript and the world’s largest software registry.

    • npm 是一个JavaScript包管理器,并且是世界上最大的软件登记处
  • discover packages of reusable code — and assemble them in powerful new ways.

    • 发现可重用代码,并集成代码包到项目中的全新的、强大方式
  • npm makes it easy for JavaScript developers to share and reuse code, and it makes it easy to update the code that you're sharing.

    • npm 让JavaScript开发者共享和重用代码变的更容易,同时也让我们更容易地更新正在被共享的代码

npm与 node.js

  • npm是Node.js默认的软件包管理系统。安装完毕node后,会默认安装好npm
  • npm本身也是基于Node.js开发的包(软件)

如何安装 NPM?

  • npm会随着Node.js自动安装,安装完毕node.js后会自动安装npm
  • 查看当前npm版本:npm -v
  • 更新npm:npm install npm@latest -g

NPM 使用

  1. https://www.npmjs.com/ 网站找到需要的包
  2. 在项目的根目录下,执行npm install 包名称安装
  3. 在node.js代码中通过 require('包名'); 加载该模块
  4. 注意:通过npm install 包名安装的包,会自动下载到当前目录下的node_modules目录下,如果该目录不存在,则创建,如果已存在则直接下载进去。
  5. 在代码中通过 require('包名'); 加载该模块

----- 上面说的这种方式叫做 本地安装。

NPM 全局安装介绍

  1. 什么是 npm 全局安装?
  • npm install 包名 -g npm 全局安装指的是把包安装成了一个命令行工具。
  // 通过npm全局安装mime
  npm install mime -g

  //安装完毕后可以在命令行中直接使用
  mime a.txt 命令来查看对应的结果
  1. npm 全局安装实际做了2件事:

  2. 下载包到一个指定的目录C:\Users\username\AppData\Roaming\npm\node_modules

  3. 创建一段命令行执行的代码。 C:\Users\username\AppData\Roaming\npm\mime -> C:\Users\steve xiaohu zhao\AppData\Roaming\npm\node_modules\mime\cli.js

NPM 安装建议

  1. 全局安装只是为了可以当做命令行使用而已

五、npm常用命令介绍

  1. install,安装包。npm install 包名

  2. uninstall,卸载包。·npm uninstall 包名`

  3. version,查看当前npm版本。npm versionnpm -v

  4. init,创建一个package.json文件。npm init

  5. 注意:当使用 npm init -y 的时候,如果当前文件夹(目录)的名字比较怪(有大写、有中文等等)就会影响npm init -y 的一步生成操作,此时需要 npm init 根据向导来生成

"模块"(Modules)和"包"(Packages)的区别

  1. A module is any file or directory that can be loaded by Node.js' require().
  • 模块可以是任何一个文件或目录(目录下可以有很多个文件),只要能被node.js通过require()即可。
  1. A package is a file or directory that is described by a package.json. This can happen in a bunch of different ways!
  • 包是一个文件或目录(目录下可以有多个文件)必须有一个package.json文件来描述,就可以是一个包。

node.js 错误调试:

  1. 当开启服务后,在浏览器中输入地址,如果出现浏览问题,首先要先看 服务器控制台是否报错。如果报错,直接根据服务器报错进行排错。

  2. 打开浏览器开发者工具中的 “网络” 部分,查看请求是否成功发出去了

  • 看一下请求报文是不是和我们想的一样
  • 响应状态码

在 html 网页中路径的含义

在 html 网页中相对路径 './' 和 绝对路径 '/'的含义

  1. "相对路径" 到底 "相对" 的是什么?
  • 相对当前请求的路径
  • 相对于吐出当前网页的路径

网页中的这个路径主要是告诉浏览器向哪个地址发起请求用的

  1. './' 表示本次请求从相对于当前页面的请求路径(即服务器返回当前页面时的请求路径)开始
  2. '/' 表示请求从根目录开始

打开浏览器来演示,最终主要体现在了请求报文的 url 上。

演示步骤

  1. 找到之前的静态html页面中带有外部样式表连接的网页
  2. 请求该网页,查看http请求报文中的请求路径

package.json 文件

package.json 文件的作用?

  1. package.json 文件是一个包说明文件(项目描述文件),用来管理组织一个包(一个项目)
  2. package.json 文件是一个 json 格式的文件
  3. 位于当前项目的根目录下

元数据

package.json 文件中常见的项有哪些?

  • name
    • 包的名字
  • version
    • 包的版本
  • description
    • 包描述
  • author
    • 包的作者
  • main
    • 包的入口js文件,从main字段这里指定的那个js文件开始执行
  • dependencies
    • 当前包依赖的其他包

如何创建一个 package.json 文件

  1. 通过 npm init 命令 或者 npm init -ynpm init -yes 命令
  2. 手动创建一个

注意

  1. 通过 npm init -ynpm init -yes 创建 package.json 文件时,执行命令所在的目录接名称中不能包含大写字母
  2. package.json 文件中,项目名称本身不能包含大写字母
  3. npm 更新新版本后,项目所在的文件夹如果包含中文等特殊字符,创建的时候不会提示一步一步的输入,直接报错。

官方介绍

  1. package.json
  2. Using a package.json

自己设计路由实现 Hacker News 网站部分功能

参考网址:https://news.ycombinator.com/

步骤

  1. 实现新闻列表页 - 首页 - /index get

  2. 实现新闻详情页 - 详情页 - /details get

  3. 实现新闻添加页 - 提交页 - /submit get
    /add get
    /add post

  4. 实现保存数据功能 - 将数据写入到 data.json 文件中

  5. 实现首页数据的动态加载 - 根据.json文件来加载数据

实现思路

规划项目目录结构

  • HackerNews
    • resources
      • css
      • images
    • views(存放html模板页面)
    • data(保存新闻数据 data.json 文件)
    • app.js 文件(该文件即我们写服务器端JavaScript代码的地方,用来处理用户请求)
    • package.json

路由设计

  1. 注意:此处要自己设计路由,而不是像模拟 Apache 静态资源服务器一样

根据不同的请求返回相应的功能

  1. 当请求 //index 时,返回 views/index.html 文件内容
  2. 当请求 /details 时,返回 views/details.html 文件内容
  3. 当请求 /submit 时,返回 views/submit.html 文件内容
  4. 当请求 /add 时,保存用户提交的新闻数据,并将重定向到index页面。
  5. 对于其他以'/resources'开头的都当做静态资源来处理。

知识点

  1. 封装render()函数,将render()函数挂载到response对象上,实现response.render()效果。
  2. 使用underscore模块中的模板引擎功能,渲染index页面中的新闻数据。
  3. 通过 url 模块来处理 get 请求
// 1. 将 req.url 通过 url 模块来处理
  var urlObj = url.parse(req.url, true);

  // 1.1 获取用户请求的URL,不带查询字符串
  // 注意:此时的reqUrl中不包含 get 的请求参数,只是pathname
  var reqUrl = urlObj.pathname.toLowerCase();

  // urlObj.query

  1. 服务器端接收 post 提交过来的数据
  2. 通过 querystring 模块将查询字符串转换为 json 对象

JSON在线格式化

JSON在线格式化

underscore模块介绍

参考描述

1、Underscore is a JavaScript library that provides a whole mess of useful functional programming helpers without extending any built-in objects. 

2、Underscore 是一个 JavaScript 工具库,它提供了一整套函数式编程的实用功能,但是没有扩展任何 JavaScript 内置对象。 他解决了这个问题:“如果我面对一个空白的 HTML 页面,并希望立即开始工作,我需要什么?” 他弥补了 jQuery 没有实现的功能,同时又是 Backbone 必不可少的部分。

Underscore 提供了100多个函数,包括常用的:map、filter、invoke — 当然还有更多专业的辅助函数,如:函数绑定、JavaScript 模板功能、创建快速索引、强类型相等测试等等。

模板语法介绍:

  • <%= %>, 中间写表达式
  • <%%>, 中间写语句

参考写法

  • 提示:underscore库建议使用'_'来命名对象,类似于jQuery使用$来命名
// 案例一:
var html = '<h1><%= name %></h1>';
var compiled = _.template(html);
var result = compiled({name: 'aaaa'});
console.log(compiled);



// 案例二:
// 构建模板字符串
var html = '<%for (var i = 0; i < 5; i++) { %><h1><%= name %></h1><% }%>';

// 编译模板
var compiled = _.template(html);

// 进行模板字符串替换
var result = compiled({name: '张三'});

// 输出后的结果
console.log(result);

underscore中_.template()函数返回值其实就是一个函数:

function(obj){
  var __t;
  var __p = '';
  var __j = Array.prototype.join,print = function () {
    __p += __j.call(arguments,'');
  };

  with(obj||{}) {
    __p += '<h1>' + ((__t = (name)) == null ? '' : __t) + '</h1>';
  }
  return __p;
}

url模块介绍

get请求时,用户请求的参数是在request的url属性中,纯字符串,使用起来并不方便

url模块可以更方便地解析用户请求的get参数

具体使用

  1. 加载模块 var url = require('url');
  2. 调用parse()方法解析
url.parse(urlString[, parseQueryString[, slashesDenoteHost]]);
var urlObj = url.parse(reqUrl, true);

// url对象的pathname属性,获取不包含查询字符串的url
// url对象的query属性中包含的就是请求字符串的键值对对象

模块化

什么是模块?

  • 每个.js文件就是一个模块
  • 从npm上下载的一个包(可能是由多个文件组成的一个实现特定功能的包)也是一个模块
  • 任何文件或目录只要可以被Node.js通过require()函数加载的都是模块
  • 每个模块就是一个独立的作用域,模块和模块之间不会互相"污染"
  • 我们可以通过编程的方式,指定某个模块要对外暴露的内容(其实就是指定require的返回值,通过require的返回值对外暴露指定内容)。这个对外暴露内容的过程也叫"导出" module.exports

什么是包?

  • 通过package.json描述的一个文件或目录(可以理解成一个实现某个功能的1个文件或多个文件,通过package.json组织起来)
  • 包不一定能被Node.js通过require()来加载,那么就不就叫模块。比如有些包中没有设置启动文件(package.json中的main字段),就不是模块。

参考链接:https://docs.npmjs.com/how-npm-works/packages

在Node.js中模主要分为:核心模块 和 文件模块

核心模块

  • http、fs、path、url、net、os、readline、......
  • 核心模块在Node.js自身源码编译时,已经编译成二进制文件
  • 部分核心模块在Node.js进程启动的时候已经默认加载到缓存里面了

文件模块

  • 文件模块可以是:.js 模块、.node模块、*.json模块,这些都是文件模块
  • 无论从npm上下载的第三方模块还是我们自己编写的模块都是文件模块

模块化的好处

  • 模块和模块之间不会出现变量"污染",一个模块就是一个作用域。
  • 模块化开发效率高、可维护性好
  • 模块化可以做到职责分离,每个模块实现一个独立的功能

模块加载

无论是核心模块还是文件模块加载都是采用require('标识符')

核心模块的加载速度是最快的

无论是 核心模块 还是 文件模块,加载过一次后都会缓存起来,第二次加载(第二次require)的时候直接从缓存中读取即可。所以模块中的代码只在第一次加载的时候执行一次,这点要注意。

核心模块只能通过 "模块名称" 来加载,例如:require('模块名称')

文件模块可以通过 require 指定路径的方式来加载(路径可以是文件路径 或 目录)

  • require('./a/b.js') 通过指定相对路径来加载模块
  • require('/a/b.js')require('c:\a\b.js') 通过指定绝对路径来加载
  • 注意:require('')加载模块的时候,相对路径永远相对于当前模块,不受node命令执行的路径影响。

通过路径的方式加载文件模块时,文件的后缀可有可无

  • 省略后缀名后,Node.js默认会以:.js、.node、.json的顺序来加载(依次拼接不同的后缀,查找并尝试加载)。
  • 建议:始终加上后缀。

npm下载的第三方模块加载

也是通过 require('模块名称') 来加载的

第三方模块名称绝对不能与 核心模块重名,否则永远加载的都是核心模块

require('模块名称') 加载非核心模块的过程

  • 通过 console.log(module.paths); 来查看

require lookup modules

require 加载模块时做了2件事

  1. 执行了模块中的代码
  2. 返回了模块中对外暴露的内容(可能是对象、函数等等)

module.exports 和 exports

在每个模块中module表示当前模块对象, 里面保存了当前模块对象的各种信息

module.exports 其实就是 require()加载模块时的返回值

exports 就是module.exports的一个引用

exports = module.exports;

特别注意:最终暴露给require的返回值的是:module.exports, 而不是exports

 // To illustrate(说明) the behavior, imagine this hypothetical implementation of require(), which is quite similar to what is actually done by require():

 function require(...) {
 var module = { exports: {} };


 ((module, exports) => {
   // Your module code here. In this example, define a function.
   function some_func() {};
   exports = some_func;
   // At this point, exports is no longer a shortcut to module.exports, and
   // this module will still export an empty default object.
   module.exports = some_func;
   // At this point, the module will now export some_func, instead of the
   // default object.
 })(module, module.exports);

 
 return module.exports;
}

下载Node.js源码,打开看下

JavaScript 的严格模式—— "use strict";'use strict';

posted @ 2021-09-02 20:59  傀儡岁月  阅读(34)  评论(0编辑  收藏  举报