node.js学习之路二(基础)
2018-07-14 本文已影响6人
w如弈如意c
关于http


1.网站的访问流程

2.node创建一个服务
let http = require('http')
let port = 8000
http.createServer((req, res) => { // 监听函数,当请求到来时,会执行回调函数
// req代表客户端,是一个可读流
// res代表服务端,是一个可写流
res.setHeader('Content-type', 'text/plain;charset=utf8')
res.write('hello')
// 调用end方法,结束响应
res.end('你好') // node是utf8写入,这样直接写在浏览器会乱码,所以需要在上面声明请求头
}).listen(port, () => {
console.log(`服务开启成功,端口为${port}`)
}) // 如果不写端口号,就是默认本机,,注意尽量使用3000以上
3.在本地服务读写文件
let http = require('http')
let fs = require('fs')
let port = 8000
http.createServer((req, res) => {
//不写编码类型buffer类型会自动转换为字符串
res.setHeader('Content-type', 'text/plain;charset=utf8')
// 如果读的文件是html且html上也有utf8的话,不需要设置请求头也会正常解析中文
fs.readFile('./1.txt', 'utf8', function(err, data) {
res.end(data)
})
}).listen(port, () => {
console.log(`服务开启成功,端口为${port}`)
})
也可以通过流的方式,(pipe)对象简写
let http = require('http')
let fs = require('fs')
let port = 8000
http.createServer((req, res) => {
res.setHeader('Content-type', 'text/plain;charset=utf8')
fs.createReadStream('1.txt').pipe(res)
}).listen(port, () => {
console.log(`服务开启成功,端口为${port}`)
})
查看请求路径
let http = require('http')
let fs = require('fs')
let url = require('url') // 把一个路径解析成一个对象
let port = 8000
http.createServer((req, res) => {
res.setHeader('Content-type', 'text/plain;charset=utf8')
fs.createReadStream('1.txt').pipe(res)
// 查看请求路径
console.log(req.url) // 这个包括了?号前和?号后的内容,如:/index.html?a=1
// 查看真正的请求路由(url)
let urlData = url.parse(req.url)
// 解析出来的对象的query就是连接上的参数,一对象的形式呈现; pathname就是真正的路由
console.log(urlData.pathname)
}).listen(port, () => {
console.log(`服务开启成功,端口为${port}`)
})
如下:如果访问的是'/',显示主页html,如果访问的是文件,将文件内容读取返回,如果访问的是文件夹,默认去找html文件,如果文件不存在,返回404
let http = require('http')
let fs = require('fs')
let url = require('url') // 把一个路径解析成一个对象
let path = require('path')
let port = 8000
http.createServer((req, res) => {
// 如下:如果访问的是'/',显示主页html,如果访问的是文件,将文件内容读取返回,如果访问的是文件夹,默认去找html文件,如果文件不存在,返回404
let {pathname, query} = url.parse(req.url, true) // true的作用是将query转换成一个对象,pathname是带'/'
fs.stat('.' + pathname, function(err, stats) {
if(err) {
res.statusCode = 404 // 找不到就是404
res.end(`${pathname} not found`)
} else if (stats.isFile) {
// 是文件的情况(这里没写头)
fs.createReadStream('.' + pathname).pipe()
} else if (stats.isDirectory()) {
// 如果是文件夹,默认查找index.html,'./'也是文件夹,获取到当前的路径和我的index.html进行拼接
let p = path.join('.' + pathname, 'index.html') // 拼出来读写的内容
fs.createWriteStream(p).pipe(res)
}
})
}).listen(port, () => {
console.log(`服务开启成功,端口为${port}`)
})
上面还有一个问题,头文件没偶遇设置,如下设置:
let http = require('http')
let fs = require('fs')
let url = require('url') // 把一个路径解析成一个对象
let path = require('path')
let port = 8000
// 获取后缀
let mine = {
'.js': 'application/javascript',
'.css': 'text/css',
'./html': 'text/html'
}
http.createServer((req, res) => {
// 如下:如果访问的是'/',显示主页html,如果访问的是文件,将文件内容读取返回,如果访问的是文件夹,默认去找html文件,如果文件不存在,返回404
let {pathname, query} = url.parse(req.url, true)
fs.stat('.' + pathname, function(err, stats) {
if(err) {
res.statusCode = 404 // 找不到就是404
res.end(`${pathname} not found`)
} else if (stats.isFile) {
// 这里可还能是js,css,html等,可以获取后缀,来确定类型
let extName = pathname.match(/\.\w+$/)[0] // 正则匹配后缀
res.setHeader('Content-type', mine[extName] + ';charset=utf8')
fs.createReadStream('.' + pathname).pipe()
} else if (stats.isDirectory()) {
// 这里头文件是html
res.setHeader('Content-type', 'text/html;charset=utf8')
let p = path.join('.' + pathname, 'index.html')
fs.createWriteStream(p).pipe(res)
}
})
}).listen(port, () => {
console.log(`服务开启成功,端口为${port}`)
})
node中间件mime,也能实现类型转化:(替换上面setHeader部分)
let mime = require('mime')
mime.getType(pathname) + '
4.fetch方法(代替ajax,用法更灵活)
fetch('/lock', {
method: 'GET'
}).then(function(res) {
// 第一个回调是promise
console.log(res.json())
}).then(function(data) {
// 第一个回调是promise的结果
console.log(data)
})
express初步学习
有了express之前手写的node能简化很多,下面简单实现
let express = require('express')
// 引用express模块,express是一个函数
let app = express() // express函数执行后,返回的是一个http的监听函数,就是http.createdServer函数
// 并在此函数上扩展了一个listen可以监听得端口
app.listen(8000, function() {
console.log(123)
})
express的路由
let express = require('express')
let app = express()
app.listen(8000)
// app监听函数上扩展了很多方法,包括get,post,delete,put等
// app.方法名('路径名',fn)
// 从上到下匹配,如果匹配到了并且结束响应,就不会往下走了
//路径指的是pathname,没有?后面的内容
// express重点就是扩展req和res的属性
app.get('/signin', function(req, res) {
res.setHeader('Content-type', 'text/html;charset=utf8')
res.end('登录')
})
app.get('/signup', function(req, res) {
res.setHeader('Content-type', 'text/html;charset=utf8')
res.end('注册')
})
// 上面都不匹配,all表示所有的方法,'*'表示所有路径
app.all('*', function(req, res) {
res.end('404')
})
exress扩展的一些req的属性
let express = require('express')
let app = express()
app.listen(8000)
// 想区分是查询一个用户还是查询所有用户
app.get('/user', function(req, res) {
console.log(req.query.id) // (express扩展的方法)
console.log(req.url) // 获取整个路径,包括?
console.log(req.path) // 路径没有?号 --(express扩展的方法)
console.log(req.headers) // 请求头,所有都是小写
console.log(req.method) // 请求的方法,所有的方法都是大写
})
上面例子优化,,将差一个和所有的方法分开,?号的路径无法区分
let express = require('express')
let app = express()
app.listen(8000)
// 如果访问/user?id=1 查一个, /user查所有,但这样路径都是/user,还是拆分
// user/1表示差一个, /user查所有,这样写就能区分差多个还是查一个
app.get('/user', function(req, res) {
res.end('select all')
})
// 表示id是占位符,必须要有,但是可以随机
// /user/1/wc => {id:1, name:wc} = params 一一对应的关系
app.get('/user/:id/:name', function(req, res) {
res.end('select one: ' + req.params.id + req.params.name)
})
分别处理参数的方法
let express = require('express')
let app = express()
app.listen(8000)
// app.pram()有拦截功能,可实现参数操作和路由分离开
// 处理id
app.pram('id', function(req, res, next) {
res.prams.id = `你的id是${req.prams.id}`
next() // 调用next()就可以向下匹配,如果在这里借宿了请求,就结束
})
// 处理name
app.pram('name', function(req, res, next) {
res.prams.name = `你的name是${req.prams.name}`
next()
})
app.get('/user/:id/:name', function(req, res) {
// express设置头文件
res.Header('Content-type','text/plain;charset=utf8')
res.end(`${res.prams.id}${res.prams.name}`)
})
中间件(middleWare)当我们访问到最终目标之前执行的内容
中间件的第一个功能, 可以进行权限判断
// 第一个参数是路径,如果不写,会对所以请求路径都回执行
let express = require('express')
let app = express()
app.listen(8000)
app.use(function(req,res, next) { // 不调用next不往下走
console.log('步骤一')
next()
})
app.use(function(req,res, next) { // 不调用next不往下走,一旦在上面调用res.end(),下面就执行结果就白搭了
console.log('步骤二')
next()
})
app.get('/user, function(req, res) {
res.Header('Content-type','text/plain;charset=utf8')
res.end('结束')
})
中间件的第二个功能就是可以对res和req属性扩充
let express = require('express')
let app = express()
app.listen(8000)
// 中间件的第一个功能, 可以进行权限判断
// 对执行路径“/user”有效
app.use("/user",function(req,res, next) { // 不调用next不往下走
console.log('步骤一')
req.a = 'aaaa'
next()
})
// 虽所有执行路径都有效
app.use(function(req,res, next) { // 不调用next不往下走,一旦在上面调用res.end(),下面就执行结果就白搭了
console.log('步骤二')
res.b = 'bbbb'
next()
})
app.get('/user, function(req, res) {
res.Header('Content-type','text/plain;charset=utf8')
console.log(req.a + res.b)
res.end('结束')
})
总结下中间件特点:
1.可以进行权限判断
2.可以对res和req属性扩充
3.第一个参数是路径,如果不写,会对所以请求路径都回执行
4.中间件要放在执行路径之前才会生效
有了中间间,我们就可以统一设置头文件了
// 通过中间件设置头文件(利用中间件不设第一个参数就是默认全部的特点)
app.get(function(req, res) {
res.Header('Content-type','text/plain;charset=utf8')
next()
})
app.get('/user', function(req, res) {
console.log(req.a + res.b)
res.end('结束')
})
app.get('/pssword', function(req, res) {
console.log(req.a + res.b)
res.end('结束')
})
错误中间件:
错误中间件放在最后面,接受4个参数,比正常中间件多一个err,err位next()中的参数
let express = require('express')
let app = express()
app.listen(8000)
// 中间件的第一个功能, 可以进行权限判断
// 第一个参数是路径,如果不写,会对所以请求路径都回执行
app.use('/pssword',function(req,res, next) {
console.log('步骤二')
res.b = 'bbbb'
next('错误')
})
app.get('/user', function(req, res) {
console.log(req.a + res.b)
res.end('结束')
})
// 错误中间件
app.get(function(err, req, res, next) {
console.log(err)
})