Bootstrap

Node.js(黑马)笔记01--day1--最简单的node执行脚本,readFile,创建服务器,核心模块,IP地址和端口号,编码格式g、get,post,路由,静态资源

0、webstom2020解决node代码不自动提示及显示警告的bug

完美解决Webstorm不支持nodejs等语法提示和补全

https://blog.csdn.net/Dobility/article/details/87563057

1、最简单的node执行脚本

创建一个js文件

var foo="hello world"
console.log(foo)

直接在cmd中进行编译执行
node xxx.js
直接会输出foo的内容

2、fs.readFile关于读文件

node里没有文件操作,要向进行读文件操作就必须映入fs核心模块
格式
fs.readFile(“内容字符串”,回到函数)

var fs=require('fs')

成功:
文件写入成功:
data是数据
error是null

失败:
文件写入失败
data是undefined没有数据
error是错误对象

案例

var fs=require('fs')//导入fs模块用于读文件操作

fs.readFile('hello.txt',function(error,data){
	console.log(data.toString())
})

改进:

var fs=require('fs')

fs.readFile('hellos.txt',function(error,data){
	if(error){
		console.log("读取文件失败")
	}else{
		console.log(data.toString())
	}
	
})
3、fs.writeFile写文件

格式:
fs.writeFile(“写入文件url”,“写入内容”,回调函数)

  • 成功:
    文件写入成功:
    error是null

  • 失败
    文件写入失败
    error就是错误对象

var fs=require('fs')

fs.writeFile("sayhello.txt","大家好,我是node.js",function(error){
	console.log("文件写入成功")
})

改进

var fs=require('fs')

fs.writeFile("sayhello.txt","大家好,我是node.js",function(error){
	if(error){
		console.log("写入失败")
	}else{
		console.log("写入成功")
	}
})
3.1、path模式拼接路径

根据服务器所使用的不同系统,拼接路径(斜杠方式不一样)

const fs= require('fs');
const path=require('path')

let newpath=path.join('e:','myproject')
console.log(newpath)

输出结果:
e:\myproject

3.2、path模式下通过__dirname获取路径

__dirname获得node当前目录

const fs= require('fs');
const path=require('path')

fs.readFile(path.join(__dirname,'b.js'),'utf8',(err,doc)=>{
  console.log(err)
  console.log(doc)
})
3.3、gulp 报异步错误

gulp时,node报node did you forget to signal async completion错误

使用ruturn 返回gulp

参考文章

const gulp=require('gulp');
const htmlmin=require('gulp-htmlmin');
const fileinclude=require('gulp-file-include')
const less=require('gulp-less')
gulp.task('first',()=>{
  console.log('人生中的第一个gulp任务');
  return gulp.src('./src/css/base.css')
    .pipe(gulp.dest('dist/css'));

});

gulp.task('htmlmin',()=>{
  return gulp.src('./src/*.html')
    .pipe(fileinclude())
    //压缩html文件中的代码
    .pipe(htmlmin({collapseWhitespace: true}))
    .pipe(gulp.dest('dist'));

})
//less语法转换,css代码压缩
gulp.task('cssmin',()=>{
  //选择css目录下的所有lss文件及css文件
  return gulp.src(['./src/css/*.less','./scr/css/*.css'])
    //将less语法转换为css语法
    .pipe(less())
    //将css代码进行压缩
    .pipe(csso())
    //将处理的结果进行输出
    .pipe(gulp.dest('dist/css'))
})

4、node创建服务器

1、加载htpp核心模块

var myhttp=require('http');

2、使用http.createServer()创建一个web服务器,返回一个server实例

var server=myhttp.createServer();

3、服务器的作用

  • 提供数据服务
  • 发请求
  • 接收请求
  • 处理请求
  • 给个反馈(发送响应)
  • 注册request请求事件
  • 当客户端请求过来,就会自动触发服务器的request请求事件,然后执行第二个参数(回调函数):
server.on('request', function (request,response) { 
	console.log('收到客户端的请求了,请求路径是:' + request.url)
	response.write("hello")
	response.write("nodjs")
	response.end()
})

request请求事件处理函数,需要接受两个参数:

  • request请求对象

    请求对象可以用来获取客户端的一些请求信息,例如请求路径request.url

  • reponse响应对象

    响应对象可以向客户端发送响应消息
    response有一个方法,write可以用来给客户端发送响应数据
    write可以使用多次,但是最后一定要使用end来结束响应,否则客户端会一直等待

可以根据不同的请求路径响应不同的结果

  • 获取请求路径
    request.url获取到的是端口号之后的那一部分路径,也就是说所有的url都是以/开头的
  • 判断处理路径响应

4、绑定端口路号启动服务器

server.listen(8848, function () { 
	console.log("服务器启动成功了,可以通过8848端口号进行访问")
})

ctrl+c结束掉服务器
在这里插入图片描述

完整代码:

var fs = require('fs')
var myhttp = require('http')
var server=myhttp.createServer();

server.on('request', function (request,response) { 
	console.log('收到客户端的请求了,请求路径是:' + request.url)
	response.write("hello")
	response.write("nodjs")
	response.end()
	//也可以是用如下简写方式
	reponse.end("hello world")
})

server.listen(8848, function () { 
	console.log("服务器启动成功了,可以同过8848端口号进行访问")
})

根据不同的请求路径返回不同的返回结果,response的响应内容只能是二进制数据或者字符串,数字,对象,数组,布尔值

var fs = require('fs')
var myhttp = require('http')
var server=myhttp.createServer();

server.on('request', function (request,response) { 
	console.log('收到客户端的请求了,请求路径是:' + request.url)
	if (request.url === "/products") {
		var products = [
			{
				name: '苹果X',
				price: 999,
			},
			{
				name: '华为X',
				price: 3399,
			},
			{
				name: '小米',
				price: 1999,
			}
		];
		//console.log(products);
		console.log(JSON.stringify(products));//数组转字符串
	} 
	
})

server.listen(8848, function () { 
	console.log("服务器启动成功了,可以同过8848端口号进行访问")
})
5、node核心模块

node为JavaScript提供给了很多服务器级别的API,这些API绝大多数都被包装到了一个具名的核心模块中了,例如:

  • fs:文件操作模块
  • http:http服务模块
  • path:路径操作模块
  • os:操作系统信息模块

这些核心模块的必须要引入才能使用,如

var fs=require'fs'

node中,模块有三种

  • 具名的核心模块,例如fs,http
  • 用户自己编写的文件模块,
    相对路径必须加 ./
    模块也就是一个js文件,使用require导入,可以省略后缀名
    支持链式导入,a导入b,b导入c,最终等同于a导入c
  • 在node中,没有全局作用域,只有模块作用域
    外部访问不到内部,内部也访问不到外部,默认都是封闭的

模块之间如何通信
require方法两个作用:

  • 1、加载文件模块并执行里面的代码
  • 2、拿到被加载文件模块到处的接口对象

在每个文件模块中都提供了一个默认对象:exports,默认是个空对象,把所有需要被外部访问的成员挂载到exports中

b.js文件

 var foo='bbb'

exports.foo = 'hello'//添加了需要被外部访问的成员
exports.add = function (x, y) { 
    return x+y
}
console.log(exports)

ex001.js

 var ret = require('./b')
console.log(ret)
console.log(ret.foo)
console.log(ret.add(10,50))
6、关于ip地址和端口号
  • ip地址用来定位计算机
  • 端口号对应具体应用软件
  • 一切需要联网的软件都会占用一个端口号
  • 端口号从0-65536之间
  • 在计算机中有些默认的端口号
  • 可以同时开启多个服务,但一定要确保不同服务占用的端口号不一致
7、设置编码格式
var fs = require('fs')
var myhttp = require('http')
var server=myhttp.createServer();

server.on('request', function (request, response) { 
	var url = request.url
	if (url === '/plain') {
		response.setHeader('Content-type', 'text/plain; charset=utf-8')
		response.end("你好 中国")
	} else if (url === '/html') { 
		response.setHeader('Content-type', 'text/html; charset=utf-8')
		response.end('<h1>hello html标签</h1>')
	}
	
	
})

server.listen(8848, function () { 
	console.log("服务器启动成功了,可以同过8848端口号进行访问")
})

Content-type资源类型:

  • text/css
  • text/plain
  • text/html
  • image/jpeg
  • image/png

案例:

var fs = require('fs')
var myhttp = require('http')
var server=myhttp.createServer();

server.on('request', function (request, response) { 
	var url = request.url
	if (url === '/') {
		fs.readFile('index.html', function (err, data) {
			if (err) {
				response.setHeader('Content-type', 'text/plain; charset=utf-8')
				response.end("文件读取失败")
			} else { 
				//data默认是二进制数据,可以通过toString转为能够识别的字符串
				//response.end支持两种数据类型,一种是二进制,一种是字符串,因此可以直接读取
				response.setHeader('Content-type', 'text/html; charset=utf-8')
				response.end(data)
			}
			
		})
	} else if (url === '/girl') { 
		fs.readFile('./gril03.jpg', function (err, data) { 
			response.setHeader('Content-type', 'image/jpeg')
			response.end(data)
		})
	}	
})

server.listen(8848, function () { 
	console.log("服务器启动成功了,可以同过8848端口号进行访问")
})
8、读取get方式传递的参数

服务器端代码

// 用于创建网站服务器的模块
const http = require('http');
// 用于处理url地址
const url = require('url');
// app对象就是网站服务器对象
const app = http.createServer();
// 当客户端有请求来的时候
app.on('request', (req, res) => {
	// 获取请求方式
	// req.method
	// console.log(req.method);
	
	// 获取请求地址
	// req.url
	// console.log(req.url);
	
	// 获取请求报文信息
	// req.headers
	// console.log(req.headers['accept']);
	
	res.writeHead(200, {
		'content-type': 'text/html;charset=utf8'
	});

	console.log(req.url);
	// 1) 要解析的url地址
	// 2) 将查询参数解析成对象形式
	let { query, pathname } = url.parse(req.url, true);
	console.log(query.name)
	console.log(query.age)

	if (pathname == '/index' || pathname == '/') {
		res.end('<h2>欢迎来到首页</h2>');
	}else if (pathname == '/list') {
		res.end('welcome to listpage');
	}else {
		res.end('not found');
	}
	
	if (req.method == 'POST') {
		res.end('post')
	} else if (req.method == 'GET') {
		res.end('get')
	}

	// res.end('<h2>hello user</h2>');
});
// 监听端口
app.listen(3000);
console.log('网站服务器启动成功');
9、读取post方式传递的参数

服务器端代码

// 用于创建网站服务器的模块
const http = require('http');
// app对象就是网站服务器对象
const app = http.createServer();
// 处理请求参数模块
const querystring = require('querystring');
// 当客户端有请求来的时候
app.on('request', (req, res) => {
	// post参数是通过事件的方式接受的
	// data 当请求参数传递的时候出发data事件
	// end 当参数传递完成的时候出发end事件
	
	let postParams = '';

	req.on('data', params => {
		postParams += params;
	});

	req.on('end', () => {
		console.log(querystring.parse(postParams));
	});

	res.end('ok');

});
// 监听端口
app.listen(3000);
console.log('网站服务器启动成功');
10、路由
// 1.引入系统模块http
// 2.创建网站服务器
// 3.为网站服务器对象添加请求事件
// 4.实现路由功能
// 	1.获取客户端的请求方式
// 	2.获取客户端的请求地址
const http = require('http');
const url = require('url');

const app = http.createServer();

app.on('request', (req, res) => {
	// 获取请求方式
	const method = req.method.toLowerCase();
	// 获取请求地址
	const pathname = url.parse(req.url).pathname;

	res.writeHead(200, {
		'content-type': 'text/html;charset=utf8'
	});

	if (method == 'get') {

		if (pathname == '/' || pathname == '/index') {
			res.end('欢迎来到首页')
		}else if (pathname == '/list') {
			res.end('欢迎来到列表页')
		}else {
			res.end('您访问的页面不存在')
		}

	}else if (method == 'post') {

	}

});

app.listen(3000);
console.log('服务器启动成功')
11、静态资源
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');
const mime = require('mime');

const app = http.createServer();

app.on('request', (req, res) => {
	// 获取用户的请求路径
	let pathname = url.parse(req.url).pathname;

	pathname = pathname == '/' ? '/default.html' : pathname;

	// 将用户的请求路径转换为实际的服务器硬盘路径
	let realPath = path.join(__dirname, 'public' + pathname);

	let type = mime.getType(realPath)

	// 读取文件
	fs.readFile(realPath, (error, result) => {
		// 如果文件读取失败
		if (error != null) {
			res.writeHead(404, {
				'content-type': 'text/html;charset=utf8'
			})
			res.end('文件读取失败');
			return;
		}

		res.writeHead(200, {
			'content-type': type
		})

		res.end(result);
	});
});

app.listen(3000);
console.log('服务器启动成功')
12、异步编程–回调函数

格式
function getData(callback){ }
函数调用
getData(()=>{ } )

可以通过回调函数拿到异步处理的结果
示例

function getData(callback){
  callback('123')
}

getData(function(n){
  console.log('callback is used')
  console.log(n)
});

另一个例子

function getMsg(callback){
  setTimeout(function () {
    callback({
      msg:'hello node.js'
    })
  },2000)

}

getMsg(function(data){
  console.log(data)
});
12.5、promise破解回调地狱

promise出现的目的是解决node.js异步编程中回调地狱的问题。实际是一个语法上的改进

  • 创建一个promise对象,在构造函数中设计回调
  • 使用then方法调用回调函数
let promise=new Promise((resolve,reject)=>{
  setTimeout(()=>{
    if (true){
      resolve({name:'zhagnsan'})
    }else{
      reject('失败了')
    }
  },2000)
})

promise.then(result=>console.log(result))//实际执行的是then里面传入的函数
.catch(error=>log(error))

另一个案例

const fs=require('fs')

let promise=new Promise((resolve,reject)=>{
  fs.readFile('./callback.js','utf8',(error,resualt)=>{
    if (error!=null){
      reject(error)//失败,想reject处理函数返传递error信息
    }else{
      resolve(resualt)//成功向resolve处理函数传递resualt结果
    }
  })
})

promise.then((result)=>{
  console.log(result)
  })
  .catch((err)=>{
    console.log(err)
  })
  

13、异步函数

异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,是代码变得清晰明了

  • 在普通函数前加上async关键字就可以将普通函数变成异步函数。
  • 异步函数默认的返回值是promise对象
  • 在异步函数内部使用throw关键字进行错误的抛出

格式为:

const fn=async ()=>{
  
}

async function fn(){
  
}

具体案例

async function fn(){
  return 123//使用return关键字替代了原有的resolve方法
}

fn().then(function (data) {
  console.log(data)
})
async function fn(){
  return 123//使用return关键字替代了原有的resolve方法
}

fn().then(function (data) {
  console.log(data)
})
.catch(function(err){
  console.log(err)
})
14、异步函数的await关键字
  • 她只能出现在异步函数中
  • await promise可以暂停异步函数的执行 等待promise对象的返回的结果后再向下执行。
async function p1(){
 return 'p1'
}
async function p2(){
  return 'p2'
}

async function p3(){
  return 'p3'
}

async function run(){
  let r1=await p1()//会等p1()执行完再来执行下面的函数
  let r2=await p2()//会等p2()执行完再来执行下面的函数
  let r3=await p3()
  console.log(r1)
  console.log(r2)
  console.log(r3)
}

run()

结果:依次输出p1,p2,p3

15、promisify对异步模块的包装
const fs=require('fs')
const promisify=require('util').promisify;//引入一个promisify的方法

const readFile=promisify(fs.readFile)//将fs.readFile进行了包装,包装成了一个异步方法
async function run(){
  let r1=await readFile('./callback.js','utf8')
  let r2=await readFile('./bewrited.txt','utf8')
  let r3=await readFile('./helloworld.js','utf8')
  console.log(r1)
  console.log(r2)
  console.log(r3)

}
run()

结果:
依次输出三个文件的内容

16、服务器端使用art-template模板
const template=require('art-template')

let ret=template.render('hello {{name}}',{
  name:'macon'
})

console.log(ret)
17、控制哪些资源可以被访问到
const http=require('http')
const fs=require('fs')


const template=require('art-template')

const server=http.createServer()

server.on('request',(req,res)=>{
  let url=req.url
  if (url==='/'){
    fs.readFile('views/index.html',(err,data)=>{
        if (err){
           return res.end('404,can not find the resource')
        }
        res.end(data)
    })
  }else if(url.indexOf('/public')===0){//控制那些资源可以被访问
    fs.readFile('.'+url,(err,data)=>{
      if (err){
        return res.end('404,没有找到需要请求的资源')
      }
      res.end(data)
    })
  }


})


server.listen('3000',()=>{
  console.log('the service is start at port 3000')
})

18、模块的导出
  • 使用exports.xxx=变量或方法的形式来导出想要导出的内容(变量或方法)
  • 使用时使用let 模块名=require(文件名)来导入想要使用的内容(变量和方法)
  • 通过模块名.变量或方法来使用这个模块的内容(变量或方法)
  • 可以使用module.exports={对象属性列表}的形式形式一次性导出多个内容(对象属性列表中的内容,即变量或方法),
    myout.js
let outer1='hello node'
let outer2=function(x,y){
  return x+y
}

module.exports={
  outer1,
  outer2
}

myin.js

const outer=require('./myout')

console.log(outer.outer1)
console.log(outer.outer2(3,5))

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;