复习
了解:
- 浏览器渲染引擎工作原理
- 浏览器访问网站过程
- Web开发本质:请求、处理、响应
- C/S 架构 和 B/S 架构
- node.js 是什么?
- node.js 有什么特点?
- node.js 安装
- node.js 开发网站 和 传统方式开发网站(PHP、JSP等)有什么区别?
- node.js REPL
- 如何进入 REPL 环境
- 如何退出 REPL 环境
- 通过创建 js 文件开发 node.js 程序
重点:
- 通过 fs 模块实现文件读写操作
- path 模块使用
__dirname
和__filename
- node.js 中异步是如何实现的?为什么说 node.js 即是单线程又是异步非阻塞 I/O 模型?
- 调用栈
- 调用队列
- 编写简单的 http 服务程序,无论请求当前网站下哪个路径,都返回 hello world
- 乱码问题。
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
- 设置显示 HTML 内容。
res.setHeader('Content-Type', 'text/html; charset=utf-8');
- 乱码问题。
补充:
- 文件操作时,无需先判断文件是否存在,直接操作即可,如果文件不存在会反应在 error 对象中
- try-catch 的使用
今日授课内容
通过 node.js 编写 http 服务程序 - 通过读取静态 HTML 文件来响应用户请求(带图片和外部CSS样式)
通过 node.js 编写 http 服务程序 - 模拟 Apache 服务器处理静态资源
- mime 第三方模块使用
在请求服务器的时候,请求的 url 就是一个标识!
request(http.IncomingMessage) 和 response(ServerResponse) 对象介绍
- request: 服务器解析用户提交的 http 请求报文,将结果解析到 request 对象中。凡是要获取和用户请求相关的数据都可以通过 request 对象获取
- response: 在服务器端用来向用户做出响应的对象。凡是需要向用户(客户端)响应的操作,都需要通过 response 对象来进行。
NPM
package.json、package-lock.json 文件介绍
- 元数据
自己设计路由,实现 HackerNews网站部分功能
- underscore 模块介绍、url 模块介绍
- 在html页面中写相对路径’./‘ 和 绝对路径 ‘/‘的含义
- 此处 ./ 相对的是吐出当前页面的url
- 通过设置 http 响应报文头实现弹框下载功能
- 设置
Content-Type: application/octet-stream
- 设置
Content-Disposition: attachment; filename=demo.txt
- 设置
其他参考
1、注意在发送不同类型的文件时,要设置好对应的
Content-Type
2、HTTP状态码参考
在 html 网页中路径的含义
在 html 网页中相对路径 ‘./‘ 和 绝对路径 ‘/‘的含义
- “相对路径” 到底 “相对” 的是什么?
- 相对当前请求的路径
- 相对于吐出当前网页的路径
网页中的这个路径主要是告诉浏览器向哪个地址发起请求用的
- ‘./‘ 表示本次请求从相对于当前页面的请求路径(即服务器返回当前页面时的请求路径)开始
- ‘/‘ 表示请求从根目录开始
打开浏览器来演示,最终主要体现在了请求报文的 url 上。
演示步骤
- 找到之前的静态html页面中带有外部样式表连接的网页
- 请求该网页,查看http请求报文中的请求路径
一、通过静态html响应用户请求
1 | // 根据用户不同请求,做出不同响应(响应 现有的 HTML 文件) |
二、模拟Apache
第一步 建立public文件夹把要用的html css 图片都放进去
第二步 下载安装第三方插件mime
- 打开 https://www.npmjs.com/package/mime
- 安装mime 命令:npm install mime (命令不一定是永久的还得看官网改变而改变)
(2后面的方法均会因版本的变化而变化与官网为准) - 引入外部模块 const mime = require(‘mime’);
- 使用方法 mime.getType(‘txt’);
第三步使用
1 |
|
三、url就是一个标示
index.html
1 | <!DOCTYPE html> |
add.js
1 |
|
四、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])
- This method must only be called once on a message and it must be called before response.end() is called.
- 这个方法在每次请求响应前都必须被调用(只能调用一次)。并且必须在end()方法调用前调用
2. 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()方法,并且会生成默认的响应头
3. 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()的设置优先
1 | // 示例代码: |
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的时候可能指3件事
- NPM 网站:https://www.npmjs.com/
- NPM 包管理库,存储了大量的JavaScript代码库
- NPM 客户端,我们所使用的npm命令行工具。使用JavaScript开发的基于node.js的命令行工具,本身也是Node的一个包。
参考图片
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 使用
- 在 https://www.npmjs.com/ 网站找到需要的包
- 在项目的根目录下,执行
npm install 包名称
安装 - 在node.js代码中通过
require('包名');
加载该模块 - 注意:通过
npm install 包名
安装的包,会自动下载到当前目录下的node_modules
目录下,如果该目录不存在,则创建,如果已存在则直接下载进去。 - 在代码中通过
require('包名');
加载该模块
—– 上面说的这种方式叫做 本地安装。
NPM 全局安装介绍
- 什么是 npm 全局安装?
npm install 包名 -g
npm 全局安装指的是把包安装成了一个命令行工具。
1 | // 通过npm全局安装mime |
npm 全局安装实际做了2件事:
下载包到一个指定的目录
C:\Users\username\AppData\Roaming\npm\node_modules
创建一段命令行执行的代码。
C:\Users\username\AppData\Roaming\npm\mime -> C:\Users\steve xiaohu zhao\AppData\Roaming\npm\node_modules\mime\cli.js
NPM 安装建议
- 全局安装只是为了可以当做命令行使用而已
五、npm常用命令介绍
- install,安装包。
npm install 包名
- uninstall,卸载包。·npm uninstall 包名`
version,查看当前npm版本。
npm version
或npm -v
init,创建一个package.json文件。
npm init
- 注意:当使用
npm init -y
的时候,如果当前文件夹(目录)的名字比较怪(有大写、有中文等等)就会影响npm init -y 的一步生成操作,此时需要 npm init 根据向导来生成
“模块”(Modules)和”包”(Packages)的区别
- A module is any file or directory that can be loaded by Node.js’
require()
.
- 模块可以是任何一个文件或目录(目录下可以有很多个文件),只要能被node.js通过require()即可。
- 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 错误调试:
当开启服务后,在浏览器中输入地址,如果出现浏览问题,首先要先看 服务器控制台是否报错。如果报错,直接根据服务器报错进行排错。
打开浏览器开发者工具中的 “网络” 部分,查看请求是否成功发出去了
- 看一下请求报文是不是和我们想的一样
- 响应状态码
六、package.json 文件
package.json 文件的作用?
- package.json 文件是一个包说明文件(项目描述文件),用来管理组织一个包(一个项目)
- package.json 文件是一个 json 格式的文件
- 位于当前项目的根目录下
元数据
package.json 文件中常见的项有哪些?
- name
- 包的名字
- version
- 包的版本
- description
- 包描述
- author
- 包的作者
- main
- 包的入口js文件,从main字段这里指定的那个js文件开始执行
- dependencies
- 当前包依赖的其他包
如何创建一个 package.json 文件
- 通过
npm init
命令 或者npm init -y
或npm init -yes
命令 - 手动创建一个
注意
- 通过
npm init -y
或npm init -yes
创建 package.json 文件时,执行命令所在的目录接名称中不能包含大写字母 - package.json 文件中,项目名称本身不能包含大写字母
- npm 更新新版本后,项目所在的文件夹如果包含中文等特殊字符,创建的时候不会提示一步一步的输入,直接报错。
官方介绍
七、自己设计路由实现 Hacker News 网站部分功能
参考网址:https://news.ycombinator.com/
步骤
- 实现新闻列表页 - 首页 - /index get
- 实现新闻详情页 - 详情页 - /details get
实现新闻添加页 - 提交页 - /submit get
/add get
/add post实现保存数据功能 - 将数据写入到 data.json 文件中
- 实现首页数据的动态加载 - 根据.json文件来加载数据
实现思路
规划项目目录结构
- HackerNews
- resources
- css
- images
- views(存放html模板页面)
- data(保存新闻数据 data.json 文件)
- app.js 文件(该文件即我们写服务器端JavaScript代码的地方,用来处理用户请求)
- package.json
- resources
路由设计
- 注意:此处要自己设计路由,而不是像模拟 Apache 静态资源服务器一样
根据不同的请求返回相应的功能
- 当请求
/
和/index
时,返回views/index.html
文件内容 - 当请求
/details
时,返回views/details.html
文件内容 - 当请求
/submit
时,返回views/submit.html
文件内容 - 当请求
/add
时,保存用户提交的新闻数据,并将重定向到index页面。 - 对于其他以’/resources’开头的都当做静态资源来处理。
知识点
- 封装
render()
函数,将render()
函数挂载到response
对象上,实现response.render()
效果。 - 使用
underscore
模块中的模板引擎功能,渲染index
页面中的新闻数据。 - 通过 url 模块来处理 get 请求
1 | // 1. 将 req.url 通过 url 模块来处理 |
- 服务器端接收 post 提交过来的数据
- 通过 querystring 模块将查询字符串转换为 json 对象