美文网首页Node.jsNode.jsNode.js专题
node.js学习之路二(基础)

node.js学习之路二(基础)

作者: w如弈如意c | 来源:发表于2018-07-14 20:57 被阅读6次

    关于http

    客户端和服务端交互示意图
    http过程示意图2
    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)
     })
    


    注:未完,待续

    相关文章

      网友评论

        本文标题:node.js学习之路二(基础)

        本文链接:https://www.haomeiwen.com/subject/rqhypftx.html