Node.js--基础

文章目录

一、Node.js是什么

Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.

1、特性

Node.js 可以解析JS代码(没有浏览器安全级别的限制)提供很多系统级别的API,如:

  • 文件的读写 (File System)
  • 进程的管理 (Process)
  • 网络通信 (HTTP/HTTPS)
  • ……

2、举例

2.1 浏览器安全级别的限制

Ajax测试

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>browser-safe-sandbox</title>
</head>
<body>
  <div>browser-safe-sandbox</div>
  <script>
    const xhr = new XMLHttpRequest()
    xhr.open('get', 'https://m.maoyan.com/ajax/moreClassicList?sortId=1&showType=3&limit=10&offset=30&optimus_uuid=A5518FF0AFEC11EAAB158D7AB0D05BBBD74C9789D9F649898982E6542C7DD479&optimus_risk_level=71&optimus_code=10', false)
    xhr.send()
  </script>
</body>
</html>

浏览器预览

browser-sync start --server --files **/* --directory
2.2 文件的读写 (File System)
const fs = require('fs')

fs.readFile('./ajax.png', 'utf-8', (err, content) => {
  console.log(content)
})
2.3 进程的管理(Process)
function main(argv) {
  console.log(argv)
}

main(process.argv.slice(2))

运行

node 2.3-process.js argv1 argv2
2.4 网络通信(HTTP/HTTPS)
const http = require("http")

http.createServer((req,res) => {
  res.writeHead(200, {
    "content-type": "text/plain"
  })
  res.write("hello nodejs")
  res.end()
}).listen(3000)

二、Node 相关工具

1、NVM: Node Version Manager

1.1 Mac 安装 nvm

https://github.com/nvm-sh/nvm/blob/master/README.md

1.2 Windows 安装 nvm

nvm-windows
nodist

2、NPM: Node Package Manager

2.1 全局安装package
$ npm install forever --global (-g)
$ forever
$ npm uninstall forever --global
$ forever

全局安装包的目录

  • Mac
/Users/felix/.nvm/versions/node/nvm各个版本/bin/
  • Windows
C:\Users\你的用户名\AppData\Roaming\npm\node_modules
2.2 本地安装package
$ cd ~/desktop
$ mkdir gp-project
$ cd gp-project
$ npm install underscore
$ npm list (ls)
2.3 package.json初始化
$ pwd
$ npm init -y
$ ls
$ cat package.json
2.4 使用package.json
$ npm install underscore --save
$ cat package.json
$ npm install lodash --save-dev
$ cat package.json
$ rm -rf node_modules
$ ls
$ npm install
$ npm uninstall underscore --save
$ npm list | grep underscore
$ cat package.json
2.5 安装指定版本的包
$ pwd
$ npm list
$ npm info underscore
$ npm view underscore versions
$ npm install underscore@1.8.0
$ npm list
$ npm uninstall underscore
$ npm list
2.6 更新本地安装的包
$ npm info underscore
$ npm view underscore versions
$ npm install underscore@1.4.4 --save-dev
$ npm list | grep gulp
$ npm outdated //~2.0.0表示patch, ^2.0.0表示minor * 表示xx最新版本
$ npm list | grep gulp
$ npm update
2.7 清除缓存
npm cache clean --force
2.8 上传自己的包
2.8.1 编写模块

保存为index.js

exports.sayHello = function(){ 
  return 'Hello World'; 
} 
2.8.2 初始化包描述文件

$ npm init
package.json

{ 
  "name": "gp19-npm", 
  "version": "1.0.1", 
  "description": "gp19 self module", 
  "main": "index.js",
  "scripts": { 
    "test": "make test" 
  }, 
  "repository": { 
    "type": "Git", 
    "url": "git+https://github.com/lurongtao/gp19-npm.git" 
  }, 
  "keywords": [ 
    "demo" 
  ], 
  "author": "Felixlu", 
  "license": "ISC", 
  "bugs": { 
    "url": "https://github.com/lurongtao/gp19-npm/issues" 
  }, 
  "homepage": "https://github.com/lurongtao/gp19-npm#readme", 
} 
2.8.3 注册npm仓库账号
https://www.npmjs.com 上面的账号
felix_lurt/qqmko09ijn
$ npm adduser
2.8.4 上传包
$ npm publish

坑:403 Forbidden

查看npm源:npm config get registry
切换npm源方法一:npm config set registry http://registry.npmjs.org
切换npm源方法二:nrm use npm
2.8.5 安装包
$ npm install gp19-npm
2.8.6 卸载包
查看当前项目引用了哪些包 :
npm ls
卸载包:
npm unpublish --force
2.8.7 使用引入包
var hello = require('gp19-npm')
hello.sayHello()
2.9 npm 脚本

Node 开发离不开 npm,而脚本功能是 npm 最强大、最常用的功能之一。

一、什么是 npm 脚本?

npm 允许在 package.json 文件里面,使用 scripts 字段定义脚本命令。

{
  // ...
  "scripts": {
    "build": "node build.js"
  }
}

二、执行顺序

如果 npm 脚本里面需要执行多个任务,那么需要明确它们的执行顺序。

script1.js

var x = 0
console.log(x)

script2.js

var y = 0
console.log(y)
"scripts": {
  "script1": "node script1.js",
  "script2": "node script2.js"
}

如果是并行执行(即同时的平行执行),可以使用 & 符号。

$ npm run script1 & npm run script2

如果是继发执行(即只有前一个任务成功,才执行下一个任务),可以使用 && 符号。

$ npm run script1 && npm run script2

三、简写形式

常用的 npm 脚本简写形式。

npm start 是 npm run start

四、变量

npm 脚本有一个非常强大的功能,就是可以使用 npm 的内部变量。

首先,通过 npm_package_ 前缀,npm 脚本可以拿到 package.json 里面的字段。比如,下面是一个 package.json。

注意:一定要在 npm 脚本中运行(如:npm run view)才可以,直接在命令行中运行JS(如:node view.js)是拿不到值的

{
  "name": "foo", 
  "version": "1.2.5",
  "scripts": {
    "view": "node view.js"
  }
}

那么,变量 npm_package_name 返回 foo,变量 npm_package_version 返回 1.2.5。

// view.js
console.log(process.env.npm_package_name); // foo
console.log(process.env.npm_package_version); // 1.2.5

上面代码中,我们通过环境变量 process.env 对象,拿到 package.json 的字段值。如果是 Bash 脚本,可以用$npm_package_name 和 $npm_package_version 取到这两个值。

npm_package_前缀也支持嵌套的package.json字段。

"repository": {
  "type": "git",
  "url": "xxx"
},
scripts: {
  "view": "echo $npm_package_repository_type"
}

上面代码中,repository 字段的 type 属性,可以通过 npm_package_repository_type 取到。

下面是另外一个例子。

"scripts": {
  "install": "foo.js"
}

上面代码中,npm_package_scripts_install 变量的值等于 foo.js。

然后,npm 脚本还可以通过 npm_config_ 前缀,拿到 npm 的配置变量,即 npm config get xxx 命令返回的值。比如,当前模块的发行标签,可以通过 npm_config_tag 取到。

"view": "echo $npm_config_tag",

注意,package.json 里面的 config 对象,可以被环境变量覆盖。

{ 
  "name" : "foo",
  "config" : { "port" : "8080" },
  "scripts" : { "start" : "node server.js" }
}

上面代码中,npm_package_config_port 变量返回的是 8080。这个值可以用下面的方法覆盖。

$ npm config set foo:port 80

最后,env命令可以列出所有环境变量。

“env”: “env”

2.10 npm 安装 git 上发布的包
# 这样适合安装公司内部的git服务器上的项目
npm install git+https://git@github.com:lurongtao/gp-project.git

# 或者以ssh的方式
npm install git+ssh://git@github.com:lurongtao/gp-project.git
2.11 cross-env 使用
2.11.1 cross-env是什么

运行跨平台设置和使用环境变量的脚本

2.11.2 出现原因

当您使用 NODE_ENV=production, 来设置环境变量时,大多数 Windows 命令提示将会阻塞(报错)。(异常是Windows上的Bash,它使用本机Bash。)换言之,Windows 不支持 NODE_ENV=production 的设置方式。

2.11.3 解决

cross-env 使得您可以使用单个命令,而不必担心为平台正确设置或使用环境变量。这个迷你的包(cross-env)能够提供一个设置环境变量的 scripts,让你能够以 Unix 方式设置环境变量,然后在 Windows 上也能兼容运行。

2.11.4 安装

npm install --save-dev cross-env

2.11.5 使用
{
  "scripts": {
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
  }
}

NODE_ENV环境变量将由 cross-env 设置
打印 process.env.NODE_ENV === ‘production’

3、NRM: npm registry manager

3.1 手工切换源
3.1.1 查看当前源
npm config get registry
3.1.2 切换淘宝源
npm config set registry https://registry.npm.taobao.org
3.2 NRM 管理源

NRM (npm registry manager)是npm的镜像源管理工具,有时候国外资源太慢,使用这个就可以快速地在 npm 源间切换。

3.2.1 安装 nrm

在命令行执行命令,npm install -g nrm,全局安装nrm。

3.2.2 使用 nrm

执行命令 nrm ls 查看可选的源。
其中,带*的是当前使用的源,上面的输出表明当前源是官方源。

3.2.3 切换 nrm

如果要切换到taobao源,执行命令nrm use taobao。

3.2.4 测试速度

你还可以通过 nrm test 测试相应源的响应时间。

nrm test

4、NPX: npm package extention

npm 从5.2版开始,增加了 npx 命令。它有很多用处,本文介绍该命令的主要使用场景。

Node 自带 npm 模块,所以可以直接使用 npx 命令。万一不能用,就要手动安装一下。

$ npm install -g npx
4.1 调用项目安装的模块

npx 想要解决的主要问题,就是调用项目内部安装的模块。比如,项目内部安装了Mocha。

$ npm install -D mocha

一般来说,调用 Mocha ,只能在项目脚本和 package.json 的scripts字段里面,如果想在命令行下调用,必须像下面这样。

# 项目的根目录下执行
$ node-modules/.bin/mocha --version

npx 就是想解决这个问题,让项目内部安装的模块用起来更方便,只要像下面这样调用就行了。

$ npx mocha --version

npx 的原理很简单,就是运行的时候,会到node_modules/.bin路径和环境变量$PATH里面,检查命令是否存在。

由于 npx 会检查环境变量$PATH,所以系统命令也可以调用。

# 等同于 ls
$ npx ls

注意,Bash 内置的命令不在$PATH里面,所以不能用。比如,cd是 Bash 命令,因此就不能用npx cd。

4.2 避免全局安装模块

除了调用项目内部模块,npx 还能避免全局安装的模块。比如,create-react-app 这个模块是全局安装,npx 可以运行它,而且不进行全局安装。

$ npx create-react-app my-react-app

上面代码运行时,npx 将 create-react-app 下载到一个临时目录,使用以后再删除。所以,以后再次执行上面的命令,会重新下载 create-react-app。

注意,只要 npx 后面的模块无法在本地发现,就会下载同名模块。比如,本地没有安装http-server模块,下面的命令会自动下载该模块,在当前目录启动一个 Web 服务。

$ npx http-server
4.3 --no-install 参数和 --ignore-existing 参数

如果想让 npx 强制使用本地模块,不下载远程模块,可以使用–no-install参数。如果本地不存在该模块,就会报错。

$ npx --no-install http-server

反过来,如果忽略本地的同名模块,强制安装使用远程模块,可以使用–ignore-existing参数。比如,本地已经安装了http-server,但还是想使用远程模块,就用这个参数。

$ npx --ignore-existing http-server

三、模块/包 与 CommonJS

1、模块/包分类

Node.js 有三类模块,即内置的模块、第三方的模块、自定义的模块。

1.1 内置的模块

Node.js 内置模块又叫核心模块,Node.js安装完成可直接使用。如:

const path = require('path')
var extname = path.extname('index.html')
console.log(extname)
1.2 第三方的Node.js模块

第三方的Node.js模块指的是为了实现某些功能,发布的npmjs.org上的模块,按照一定的开源协议供社群使用。如:

npm install chalk
const chalk = require('chalk')
console.log(chalk.blue('Hello world!'))
1.3 自定义的Node.js模块

自定义的Node.js模块,也叫文件模块,是我们自己写的供自己使用的模块。同时,这类模块发布到npmjs.org上就成了开源的第三方模块。

自定义模块是在运行时动态加载,需要完整的路径分析、文件定位、编译执行过程、速度相比核心模块稍微慢一些,但是用的非常多。

1.3.1 模块定义、接口暴露和引用接口

我们可以把公共的功能 抽离成为一个单独的 js 文件 作为一个模块,默认情况下面这个模块里面的方法或者属性,外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性,就必须在模块里面通过 exports 或者 module.exports 暴露属性或者方法。

m1.js:

const name = 'gp19'

const sayName = () => {
  console.log(name)
}

console.log('module 1')

// 接口暴露方法一:
module.exports = {
  say: sayName
}

// 接口暴露方法二:
exports.say = sayName

// 错误!
exports = {
  say: sayName
}

main.js:

const m1 = require('./m1')
m1.say()
1.3.2 模块的循环引用

由于 exports 使用方式方式不对,会在两个不同 js 循环引用的情况下,导致其中一个 js 无法获取另外一个 js 的方法,从而导致执行报错。如:

  • a.js
exports.done = false
const b = require('./b.js')
console.log('in a, b.done = %j', b.done)
exports.done = true
console.log('a done')
  • b.js
console.log('b starting')
exports.done = false
const a = require('./a.js')
console.log('in b, a.done = %j', a.done)
exports.done = true
console.log('b done')
  • main.js
console.log('main starting')
const a = require('./a.js')
const b = require('./b.js')
console.log('in main, a.done = %j, b.done = %j', a.done, b.done)

main.js 首先会 load a.js, 此时执行到const b = require(‘./b.js’);的时候,程序会转去loadb.js, 在b.js中执行到const a = require(‘./a.js’); 为了防止无限循环,将a.jsexports的未完成副本返回到b.js模块。然后b.js完成加载,并将其导出对象提供给a.js模块。

我们知道nodeJs的对每个js文件进行了一层包装称为module,module中有一个属性exports,当调用require(‘a.js’)的时候其实返回的是module.exports对象,module.exports初始化为一个{}空的object,所以在上面的例子中,执行到b.js中const a = require(‘./a.js’);时不会load新的a module, 而是将已经load但是还未完成的a module的exports属性返回给b module,所以b.js拿到的是a module的exports对象,即:{done:false}, 虽然在a.js中exports.done被修改成了true,但是由于此时a.js未load完成,所以在b.js输出的a module的属性done为false,而在main.js中输出的a module的属性done为true. Nodejs通过上面这种返回未完成exports对象来解决循环引用的问题。

四、常用内置模块

这里介绍几个常用的内置模块:url, querystring, http, events, fs, stream, readline, crypto, zlib

1、url

1.1 parse

url.parse(urlString[, parseQueryString[, slashesDenoteHost]])

const url = require('url')
const urlString = 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
const parsedStr = url.parse(urlString)
console.log(parsedStr)
1.2 format

url.format(urlObject)

const url = require('url')
const urlObject = {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: 'www.baidu.com:443',
  port: '443',
  hostname: 'www.baidu.com',
  hash: '#tag=110',
  search: '?id=8&name=mouse',
  query: { id: '8', name: 'mouse' },
  pathname: '/ad/index.html',
  path: '/ad/index.html?id=8&name=mouse',
  href: 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
}
const parsedObj = url.format(urlObject)
console.log(parsedObj)
1.3 resolve

url.resolve(from, to)

const url = require('url')
var a = url.resolve('/one/two/three', 'four')
var b = url.resolve('http://example.com/', '/one')
var c = url.resolve('http://example.com/one', '/two')
console.log(a + "," + b + "," + c)

2、querystring

2.1 parse

querystring.parse(str[, sep[, eq[, options]]])

const querystring = require('querystring')
var qs = 'x=3&y=4'
var parsed = querystring.parse(qs)
console.log(parsed)
2.2 stringify

querystring.stringify(obj[, sep[, eq[, options]]])

const querystring = require('querystring')
var qo = {
  x: 3,
  y: 4
}
var parsed = querystring.stringify(qo)
console.log(parsed)
2.3 escape/unescape

querystring.escape(str)

const querystring = require('querystring')
var str = 'id=3&city=北京&url=https://www.baidu.com'
var escaped = querystring.escape(str)
console.log(escaped)

querystring.unescape(str)

const querystring = require('querystring')
var str = 'id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com'
var unescaped = querystring.unescape(str)
console.log(unescaped)

3、http/https

3.1创建web服务器的基本步骤:
  • 导入http模块
const http = require('http')
  • 创建web实例
const server = http.createServer()
  • 为服务器实例绑定request事件,监听客户端请求
//使用服务器实例的.on()方法就能为服务器绑定request事件

sever.on('request',(req,res)=>{
//当客户端请求的时候,会触发request事件
console.log('someone visit our web server')
})
  • 启动服务器
    调用服务器实例的.listen()方法,即可启动当前的web服务器实例:
//调用sever.listen(端口号,cb回调)方法,即可启动web服务器
server.listen(80,()=>{
console.log('http server running at http://')})
停止服务器

ctrl c 停止服务器

3.2 req 请求

只要服务器接收到客户端的请求,就会调用server.on()为服务器绑定的request事件处理函数。如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下方式:

req 请求对象,包含客户端的相关数据和属性
req.url是客户端请求的URL地址
req.method是客户端的method请求类型。

3.3 res响应对象

在服务器的request事件处理函数中,如果想要访问与服务器相关的数据和属性,可以使用如下方式:

res是响应对象,包含与服务器相关的数据和属性,比如要发送到客户端的字符串
res.writeHead(statusCode,[headers]):向请求的客户端发送响应头,statusCode表示HTTP的状态码如:200(请求成功);404(未找到)等;headers表示响应头部的每个属性,该函数在一个请求内最多只能调用一次,如果不调用,则会自动生成一个响应头。
res.write(data,[encording]):向请求客户端发送响应内容:data:是一个buffer或者是字符串,表示要发送的内容,如果data是字符串,需要指定encording来说明编码方式,默认:utf-8
res.end(data,[encording]):结束响应,当要返回的值被发送完毕后,该函数必须被调用一次,如果不调用,客户端永远在等待状态。
res.setHeader(‘constent-Type’,‘text/html;charset=utf-8’) 解决中文乱码。constent-Type编码格式解析,

3.3 get
var http = require('http')
var https = require('https')

// 1、接口 2、跨域
const server = http.createServer((request, response) => {
  var url = request.url.substr(1)
  
  var data = ''

  response.writeHeader(200, {
    'content-type': 'application/json;charset=utf-8',
    'Access-Control-Allow-Origin': '*'
  })

  https.get(`https://m.lagou.com/listmore.json${url}`, (res) => {

    res.on('data', (chunk) => {
      data += chunk
    })

    res.on('end', () => {
      response.end(JSON.stringify({
        ret: true,
        data
      }))
    })
  })

})

server.listen(8080, () => {
  console.log('localhost:8080')
})
3.2 post:服务器提交(攻击)
const https = require('https')
const querystring = require('querystring')

const postData = querystring.stringify({
  province: '上海',
  city: '上海',
  district: '宝山区',
  address: '同济支路199号智慧七立方3号楼2-4层',
  latitude: 43.0,
  longitude: 160.0,
  message: '求购一条小鱼',
  contact: '13666666',
  type: 'sell',
  time: 1571217561
})

const options = {
  protocol: 'https:',
  hostname: 'ik9hkddr.qcloud.la',
  method: 'POST',
  port: 443,
  path: '/index.php/trade/add_item',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData)
  }
}

function doPost() {
  let data
  
  let req = https.request(options, (res) => {
    res.on('data', chunk => data += chunk)
    res.on('end', () => {
      console.log(data)
    })
  })
  
  req.write(postData)
  req.end()
}

// setInterval(() => {
//   doPost()
// }, 1000)
3.3 跨域:jsonp
const http = require('http')
const url = require('url')

const app = http.createServer((req, res) => {
  let urlObj = url.parse(req.url, true)

  switch (urlObj.pathname) {
    case '/api/user':
      res.end(`${urlObj.query.cb}({"name": "gp145"})`)
      break
    default:
      res.end('404.')
      break
  }
})

app.listen(8080, () => {
  console.log('localhost:8080')
})
3.4 跨域:CORS
const http = require('http')
const url = require('url')
const querystring = require('querystring')

const app = http.createServer((req, res) => {
  let data = ''
  let urlObj = url.parse(req.url, true)

  res.writeHead(200, {
    'content-type': 'application/json;charset=utf-8',
    'Access-Control-Allow-Origin': '*'
  })

  req.on('data', (chunk) => {
    data += chunk
  })

  req.on('end', () => {
    responseResult(querystring.parse(data))
  })

  function responseResult(data) {
    switch (urlObj.pathname) {
      case '/api/login':
        res.end(JSON.stringify({
          message: data
        }))
        break
      default:
        res.end('404.')
        break
    }
  }
})

app.listen(8080, () => {
  console.log('localhost:8080')
})
3.5 跨域:middleware(http-proxy-middware)
const http = require('http')
const proxy = require('http-proxy-middleware')

http.createServer((req, res) => {
  let url = req.url

  res.writeHead(200, {
    'Access-Control-Allow-Origin': '*'
  })

  if (/^\/api/.test(url)) {
    let apiProxy = proxy('/api', { 
      target: 'https://m.lagou.com',
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      }
    })
  
    // http-proy-middleware 在Node.js中使用的方法
    apiProxy(req, res)
  } else {
    switch (url) {
      case '/index.html':
        res.end('index.html')
        break
      case '/search.html':
        res.end('search.html')
        break
      default:
        res.end('[404]page not found.')
    }
  }
}).listen(8080)
3.6 爬虫
const https = require('https')
const http = require('http')
const cheerio = require('cheerio')

http.createServer((request, response) => {
  response.writeHead(200, {
    'content-type': 'application/json;charset=utf-8'
  })

  const options = {
    protocol: 'https:',
    hostname: 'maoyan.com',
    port: 443,
    path: '/',
    method: 'GET'
  }
  
  const req = https.request(options, (res) => {
    let data = ''
    res.on('data', (chunk) => {
      data += chunk
    })
  
    res.on('end', () => {
      filterData(data)
    })
  })
  
  function filterData(data) {
    let $ = cheerio.load(data)
    let $movieList = $('.movie-item')
    let movies = []
    $movieList.each((index, value) => {
      movies.push({
        title: $(value).find('.movie-title').attr('title'),
        score: $(value).find('.movie-score i').text(),
      })
    })
    
    response.end(JSON.stringify(movies))
  }
  
  req.end()
}).listen(9000)

4、Events

const EventEmitter = require('events')

class MyEventEmitter extends EventEmitter {}

const event = new MyEventEmitter()

event.on('play', (movie) => {
  console.log(movie)
})

event.emit('play', '我和我的祖国')
event.emit('play', '中国机长')

5、File System

const fs = require('fs')
const fsP = require('fs').promises

// 创建文件夹
fs.mkdir('./logs', (err) => {
  console.log('done.')
})

// 文件夹改名
fs.rename('./logs', './log', () => {
  console.log('done')
})

// 删除文件夹
fs.rmdir('./log', () => {
  console.log('done.')
})

// 写内容到文件里
fs.writeFile(
  './logs/log1.txt',
  'hello',
  // 错误优先的回调函数
  (err) => {
    if (err) {
      console.log(err.message)
    } else {
      console.log('文件创建成功')
    }
  }
)

// 给文件追加内容
fs.appendFile('./logs/log1.txt', '\nworld', () => {
  console.log('done.')
})

// 读取文件内容
fs.readFile('./logs/log1.txt', 'utf-8', (err, data) => {
  console.log(data)
})

// 删除文件
fs.unlink('./logs/log1.txt', (err) => {
  console.log('done.')
})

// 批量写文件
for (var i = 0; i < 10; i++) {
  fs.writeFile(`./logs/log-${i}.txt`, `log-${i}`, (err) => {
    console.log('done.')
  })
}

// 读取文件/目录信息
fs.readdir('./', (err, data) => {
  data.forEach((value, index) => {
    fs.stat(`./${value}`, (err, stats) => {
      // console.log(value + ':' + stats.size)
      console.log(value + ' is ' + (stats.isDirectory() ? 'directory' : 'file'))
    })
  })
})

// 同步读取文件
try {
  const content = fs.readFileSync('./logs/log-1.txt', 'utf-8')
  console.log(content)
  console.log(0)
} catch (e) {
  console.log(e.message)
}

console.log(1)

// 异步读取文件:方法一
fs.readFile('./logs/log-0.txt', 'utf-8', (err, content) => {
  console.log(content)
  console.log(0)
})
console.log(1)

// 异步读取文件:方法二
fs.readFile('./logs/log-0.txt', 'utf-8').then(result => {
  console.log(result)
})

// 异步读取文件:方法三
function getFile() {
  return new Promise((resolve) => {
    fs.readFile('./logs/log-0.txt', 'utf-8', (err, data) => {
      resolve(data)
    })
  })
}

;(async () => {
  console.log(await getFile())
})()

// 异步读取文件:方法四
const fsp = fsP.readFile('./logs/log-1.txt', 'utf-8').then((result) => {
  console.log(result)
})

console.log(fsP)

// watch 监测文件变化
fs.watch('./logs/log-0.txt', () => {
  console.log(0)
})

6、Stream

const fs = require('fs')

const readstream = fs.createReadStream('./note.txt')
const writestream = fs.createWriteStream('./note2.txt')

writestream.write(readstream)

7、Zlib

const fs = require('fs')
const zlib = require('zlib')

const gzip = zlib.createGzip()

const readstream = fs.createReadStream('./note.txt')
const writestream = fs.createWriteStream('./note2.txt')

readstream
  .pipe(gzip)
  .pipe(writestream)

writestream.write(readstream)

8、ReadLine

const readline = require('readline')

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})

rl.question('What do you think of Node.js? ', (answer) => {
  // TODO: Log the answer in a database
  console.log(`Thank you for your valuable feedback: ${answer}`)

  rl.close()
})

9、Crypto

const crypto = require('crypto')

const secret = 'abcdefg'
const hash = crypto.createHmac('sha256', secret)
                   .update('I love you')
                   .digest('hex')
console.log(hash)

四、路由

var http = require('http')
var fs = require('fs')

http.createServer( function ( req, res ) {

  switch ( req.url ) {
    case '/home':
      res.write('home')
      res.end()
      break
    case '/mine':
      res.write('mine')
      res.end()
      break
    case '/login': 
      fs.readFile( './static/login.html',function ( error , data ) {
        if ( error ) throw error  
        res.write( data )
        res.end()
      })
      break
    case '/fulian.jpg':
      fs.readFile( './static/fulian.jpg', 'binary', function( error , data ) {
        if( error ) throw error 
        res.write( data, 'binary' )
        res.end()
      })
      break
    default: 
      break
   }

 }).listen( 8000, 'localhost', function () {
   console.log( '服务器运行在: http://localhost:8000' )
 })

五、静态资源服务

5.1 readStaticFile

/modules/readStaticFile.js

// 引入依赖的模块
var path = require('path')
var fs = require('fs')
var mime = require('mime')

function readStaticFile(res, filePathname) {

  var ext = path.parse(filePathname).ext
  var mimeType = mime.getType(ext)

  // 判断路径是否有后缀, 有的话则说明客户端要请求的是一个文件 
  if (ext) {
    // 根据传入的目标文件路径来读取对应文件
    fs.readFile(filePathname, (err, data) => {
    // 错误处理
      if (err) {
        res.writeHead(404, { "Content-Type": "text/plain" })
        res.write("404 - NOT FOUND")
        res.end()
      } else {
        res.writeHead(200, { "Content-Type": mimeType })
        res.write(data)
        res.end()
      }
    });
    // 返回 true 表示, 客户端想要的 是 静态文件
    return true
  } else {
    // 返回 false 表示, 客户端想要的 不是 静态文件
    return false
  }
}

// 导出函数
module.exports = readStaticFile

5.2 server

/server.js

// 引入相关模块
var http = require('http');
var url = require('url');
var path = require('path');
var readStaticFile = require('./modules/readStaticFile');

// 搭建 HTTP 服务器
var server = http.createServer(function(req, res) {
  var urlObj = url.parse(req.url);
  var urlPathname = urlObj.pathname;
  var filePathname = path.join(__dirname, "/public", urlPathname);

  // 读取静态文件
  readStaticFile(res, filePathname);
});

// 在 3000 端口监听请求
server.listen(3000, function() {
  console.log("服务器运行中.");
  console.log("正在监听 3000 端口:")
})

5.3 最终目录结构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值