前端学习之路--node.js(一)

  • node.js                                         下一篇      node.js(二)

  1. Node.js 是什么
      + JavaScript 运行时
      + 既不是语言,也不是框架,它是一个平台
  2. Node.js 中的 JavaScript
      + 没有 BOM、DOM
    console.log(window)
    console.log(document)

      + EcmaScript 基本的 JavaScript 语言部分
      + 在 Node 中为 JavaScript 提供了一些服务器级别的 API
        * 文件操作的能力
        * http 服务的能力
  3. 读取文件

    浏览器中的 JavaScript 是没有文件操作的能力的
     但是 Node 中的 JavaScript 具有文件操作的能力

     fs 是 file-system 的简写,就是文件系统的意思
     在 Node 中如果想要进行文件操作,就必须引入 fs 这个核心模块
    在 fs 这个核心模块中,就提供了所有的文件操作相关的 API
    例如:fs.readFile 就是用来读取文件的
    1. 使用 require 方法加载 fs 核心模块
     

    var fs = require('fs')

    2. 读取文件
     

    //    第一个参数就是要读取的文件路径
    //    第二个参数是一个回调函数
    //          
    //        成功
    //          data 数据
    //          error null
    //        失败
    //          data undefined没有数据
    //          error 错误对象
    
    fs.readFile('./data/a.txt', function (error, data) {
      // 
      // 文件中存储的其实都是二进制数据 0 1
      // 这里为什么看到的不是 0 和 1 呢?原因是二进制转为 16 进制了
      // 但是无论是二进制01还是16进制,人类都不认识
      // 所以我们可以通过 toString 方法把其转为我们能认识的字符
      // console.log(data)
    
      // console.log(error)
      // console.log(data)
    
      // 在这里就可以通过判断 error 来确认是否有错误发生
      if (error) {
        console.log('读取文件失败了')
      } else {
        console.log(data.toString())
      }
    })
    

     

  4. 浏览器是不认识node.js代码的

    
    
    
      
      Document
    
    
      
      
      
    
    

     

  5. 写文件

    var fs = require('fs')
    
    // $.ajax({
    //   ...
    //   success: function (data) {
        
    //   }
    // })
    
    // 第一个参数:文件路径
    // 第二个参数:文件内容
    // 第三个参数:回调函数
    //    error
    //    
    //    成功:
    //      文件写入成功
    //      error 是 null
    //    失败:
    //      文件写入失败
    //      error 就是错误对象
    fs.writeFile('./data/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
      // console.log('文件写入成功')
      // console.log(error)
      if (error) {
        console.log('写入失败')
      } else {
        console.log('写入成功了')
      }
    })
    

     

  6. http

    // 接下来,我们要干一件使用 Node 很有成就感的一件事儿
    // 你可以使用 Node 非常轻松的构建一个 Web 服务器
    // 在 Node 中专门提供了一个核心模块:http
    // http 这个模块的职责就是帮你创建编写服务器的
    
    // 1. 加载 http 核心模块
    var http = require('http')
    
    // 2. 使用 http.createServer() 方法创建一个 Web 服务器
    //    返回一个 Server 实例
    var server = http.createServer()
    
    // 3. 服务器要干嘛?
    //    提供服务:对 数据的服务
    //    发请求
    //    接收请求
    //    处理请求
    //    给个反馈(发送响应)
    //    注册 request 请求事件
    //    当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
    server.on('request', function () {
      console.log('收到客户端的请求了')
    })
    
    // 4. 绑定端口号,启动服务器
    server.listen(3000, function () {
      console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
    })
    

     

  7. http-res

    var http = require('http')
    
    var server = http.createServer()
    
    // request 请求事件处理函数,需要接收两个参数:
    //    Request 请求对象
    //        请求对象可以用来获取客户端的一些请求信息,例如请求路径
    //    Response 响应对象
    //        响应对象可以用来给客户端发送响应消息
    server.on('request', function (request, response) {
      // http://127.0.0.1:3000/ /
      // http://127.0.0.1:3000/a /a
      // http://127.0.0.1:3000/foo/b /foo/b
      console.log('收到客户端的请求了,请求路径是:' + request.url)
    
      // response 对象有一个方法:write 可以用来给客户端发送响应数据
      // write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待
      response.write('hello')
      response.write(' nodejs')
    
      // 告诉客户端,我的话说完了,你可以呈递给用户了
      response.end()
    
      // 由于现在我们的服务器的能力还非常的弱,无论是什么请求,都只能响应 hello nodejs
      // 思考:
      //  我希望当请求不同的路径的时候响应不同的结果
      //  例如:
      //  / index
      //  /login 登陆
      //  /register 注册
      //  /haha 哈哈哈
    })
    
    server.listen(3000, function () {
      console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
    })
    

     

  8. http-url-res 

    var http = require('http')
    
    // 1. 创建 Server
    var server = http.createServer()
    
    // 2. 监听 request 请求事件,设置请求处理函数
    server.on('request', function (req, res) {
      console.log('收到请求了,请求路径是:' + req.url)
      console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort)
    
      // res.write('hello')
      // res.write(' world')
      // res.end()
    
      // 上面的方式比较麻烦,推荐使用更简单的方式,直接 end 的同时发送响应数据
      // res.end('hello nodejs')
    
      // 根据不同的请求路径发送不同的响应结果
      // 1. 获取请求路径
      //    req.url 获取到的是端口号之后的那一部分路径
      //    也就是说所有的 url 都是以 / 开头的
      // 2. 判断路径处理响应
    
      var url = req.url
    
      if (url === '/') {
        res.end('index page')
      } else if (url === '/login') {
        res.end('login page')
      } else if (url === '/products') {
        var products = [{
            name: '苹果 X',
            price: 8888
          },
          {
            name: '菠萝 X',
            price: 5000
          },
          {
            name: '小辣椒 X',
            price: 1999
          }
        ]
    
        // 响应内容只能是二进制数据或者字符串
        //  数字
        //  对象
        //  数组
        //  布尔值
        res.end(JSON.stringify(products))
      } else {
        res.end('404 Not Found.')
      }
    })
    
    // 3. 绑定端口号,启动服务
    server.listen(3000, function () {
      console.log('服务器启动成功,可以访问了。。。')
    })
    

     

  9. node.js中的js-核心模块(1) 

    // 用来获取机器信息的
    var os = require('os')
    
    // 用来操作路径的
    var path = require('path')
    
    // 获取当前机器的 CPU 信息
    console.log(os.cpus())
    
    // memory 内存
    console.log(os.totalmem())
    
    // 获取一个路径中的扩展名部分
    // extname extension name
    console.log(path.extname('c:/a/b/c/d/hello.txt'))
    

     

  10. ip地址和端口号

    // ip 地址用来定位计算机
    // 端口号用来定位具体的应用程序
    // 所有需要联网通信的应用程序都会占用一个端口号
    
    var http = require('http')
    
    var server = http.createServer()
    
    // 2. 监听 request 请求事件,设置请求处理函数
    server.on('request', function (req, res) {
      console.log('收到请求了,请求路径是:' + req.url)
      console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort)
    
      res.end('hello nodejs')
    })
    
    server.listen(5000, function () {
      console.log('服务器启动成功,可以访问了。。。')
    })
    

     

  11.  HTTP-content-type

    // require
    // 端口号
    
    var http = require('http')
    
    var server = http.createServer()
    
    server.on('request', function (req, res) {
      // 在服务端默认发送的数据,其实是 utf8 编码的内容
      // 但是浏览器不知道你是 utf8 编码的内容
      // 浏览器在不知道服务器响应内容的编码的情况下会按照当前操作系统的默认编码去解析
      // 中文操作系统默认是 gbk
      // 解决方法就是正确的告诉浏览器我给你发送的内容是什么编码的
      // 在 http 协议中,Content-Type 就是用来告知对方我给你发送的数据内容是什么类型
      // res.setHeader('Content-Type', 'text/plain; charset=utf-8')
      // res.end('hello 世界')
    
      var url = req.url
    
      if (url === '/plain') {
        // text/plain 就是普通文本
        res.setHeader('Content-Type', 'text/plain; charset=utf-8')
        res.end('hello 世界')
      } else if (url === '/html') {
        // 如果你发送的是 html 格式的字符串,则也要告诉浏览器我给你发送是 text/html 格式的内容
        res.setHeader('Content-Type', 'text/html; charset=utf-8')
        res.end('

    hello html 点我

    ') } }) server.listen(3000, function () { console.log('Server is running...') })

     

  12. http-fs

    // 1. 结合 fs 发送文件中的数据
    // 2. Content-Type
    //    http://tool.oschina.net/commons
    //    不同的资源对应的 Content-Type 是不一样的
    //    图片不需要指定编码
    //    一般只为字符数据才指定编码
    
    var http = require('http')
    var fs = require('fs')
    
    var server = http.createServer()
    
    server.on('request', function (req, res) {
      // / index.html
      var url = req.url
    
      if (url === '/') {
        // 肯定不这么干
        // res.end('Document

    首页

    /html>') // 我们要发送的还是在文件中的内容 fs.readFile('./resource/index.html', function (err, data) { if (err) { res.setHeader('Content-Type', 'text/plain; charset=utf-8') res.end('文件读取失败,请稍后重试!') } else { // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串 // res.end() 支持两种数据类型,一种是二进制,一种是字符串 res.setHeader('Content-Type', 'text/html; charset=utf-8') res.end(data) } }) } else if (url === '/xiaoming') { // url:统一资源定位符 // 一个 url 最终其实是要对应到一个资源的 fs.readFile('./resource/ab2.jpg', function (err, data) { if (err) { res.setHeader('Content-Type', 'text/plain; charset=utf-8') res.end('文件读取失败,请稍后重试!') } else { // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串 // res.end() 支持两种数据类型,一种是二进制,一种是字符串 // 图片就不需要指定编码了,因为我们常说的编码一般指的是:字符编码 res.setHeader('Content-Type', 'image/jpeg') res.end(data) } }) } }) server.listen(3000, function () { console.log('Server is running...') })

     

  13. http-helloworld

    var http = require('http')
    var fs = require('fs')
    
    // 1. 创建 Server
    var server = http.createServer()
    
    // 2. 监听 Server 的 request 请求事件,设置请求处理函数
    //    请求
    //      处理
    //    响应
    //    一个请求对应一个响应,如果在一个请求的过程中,已经结束响应了,则不能重复发送响应。
    //    没有请求就没有响应。
    // 
    // 咱们以前使用过 Apache 服务器软件,这个软件默认有一个 www 目录,所有存放在 www 目录中的资源都可以通过网址来浏览
    // 127.0.0.1:80/a.txt
    // 127.0.0.1:80/index.html
    // 127.0.0.1:80/apple/login.html
    
    var wwwDir = 'D:/Movie/www'
    
    server.on('request', function (req, res) {
      var url = req.url
      // / index.html
      // /a.txt wwwDir + /a.txt
      // /apple/login.html wwwDir + /apple/login.html
      // /img/ab1.jpg wwwDir + /img/ab1.jpg
      if (url === '/') {
        fs.readFile(wwwDir + '/index.html', function (err, data) {
          // if (err) {
          //   res.end('404 Not Found.')
          // } else {
    
          // }
    
          if (err) {
            // return 有两个作用:
            //  1. 方法返回值
            //  2. 阻止代码继续往后执行
            return res.end('404 Not Found.')
          }
          res.end(data)
        })
      } else if (url === '/a.txt') {
        fs.readFile(wwwDir + '/a.txt', function (err, data) {
          if (err) {
            return res.end('404 Not Found.')
          }
          res.end(data)
        })
      } else if (url === '/index.html') {
        fs.readFile(wwwDir + '/index.html', function (err, data) {
          if (err) {
            return res.end('404 Not Found.')
          }
          res.end(data)
        })
      } else if (url === '/apple/login.html') {
        fs.readFile(wwwDir + '/apple/login.html', function (err, data) {
          if (err) {
            return res.end('404 Not Found.')
          }
          res.end(data)
        })
      }
    })
    
    // 3. 绑定端口号,启动服务
    server.listen(3000, function () {
      console.log('running...')
    })
    

     

  14. 像Apache一样

    var http = require('http')
    var fs = require('fs')
    
    var server = http.createServer()
    
    var wwwDir = 'D:/Movie/www'
    
    server.on('request', function (req, res) {
      var url = req.url
      // / index.html
      // /a.txt wwwDir + /a.txt
      // /apple/login.html wwwDir + /apple/login.html
      // /img/ab1.jpg wwwDir + /img/ab1.jpg
      
    
      var filePath = '/index.html'
      if (url !== '/') {
        filePath = url
      }
    
      fs.readFile(wwwDir + filePath, function (err, data) {
        if (err) {
          return res.end('404 Not Found.')
        }
        res.end(data)
      })
    })
    
    // 3. 绑定端口号,启动服务
    server.listen(3000, function () {
      console.log('running...')
    })
    

     

  15. Apache-目录列表

    var http = require('http')
    var fs = require('fs')
    
    var server = http.createServer()
    
    var wwwDir = 'D:/Movie/www'
    
    server.on('request', function (req, res) {
      var url = req.url
      fs.readFile('./template.html', function (err, data) {
        if (err) {
          return res.end('404 Not Found.')
        }
        // 1. 如何得到 wwwDir 目录列表中的文件名和目录名
        //    fs.readdir
        // 2. 如何将得到的文件名和目录名替换到 template.html 中
        //    2.1 在 template.html 中需要替换的位置预留一个特殊的标记(就像以前使用模板引擎的标记一样)
        //    2.2 根据 files 生成需要的 HTML 内容
        // 只要你做了这两件事儿,那这个问题就解决了
        fs.readdir(wwwDir, function (err, files) {
          if (err) {
            return res.end('Can not find www dir.')
          }
    
          // 2.1 生成需要替换的内容
          var content = ''
          files.forEach(function (item) {
            // 在 EcmaScript 6 的 ` 字符串中,可以使用 ${} 来引用变量
            content += `
              
                ${item}/
                
                2017/11/2 上午10:32:47
              
            `
          })
    
          // 2.3 替换
          data = data.toString()
          data = data.replace('^_^', content)
    
          // 3. 发送解析替换过后的响应数据
          res.end(data)
        })
      })
    })
    server.listen(3000, function () {
      console.log('running...')
    })
    

     

  16. 读取目录

    var fs = require('fs')
    
    fs.readdir('D:/Movie/www', function (err, files) {
      if (err) {
        return console.log('目录不存在')
      }
      console.log(files)
    })
    

     

  17. 在node中使用模板引擎

    // art-template
    // art-template 不仅可以在浏览器使用,也可以在 node 中使用
    
    // 安装:
    //    npm install art-template
    //    该命令在哪执行就会把包下载到哪里。默认会下载到 node_modules 目录中
    //    node_modules 不要改,也不支持改。
    
    // 在 Node 中使用 art-template 模板引擎
    // 模板引起最早就是诞生于服务器领域,后来才发展到了前端。
    // 
    // 1. 安装 npm install art-template
    // 2. 在需要使用的文件模块中加载 art-template
    //    只需要使用 require 方法加载就可以了:require('art-template')
    //    参数中的 art-template 就是你下载的包的名字
    //    也就是说你 isntall 的名字是什么,则你 require 中的就是什么
    // 3. 查文档,使用模板引擎的 API
    
    
    var template = require('art-template')
    var fs = require('fs')
    
    // 这里不是浏览器
    // template('script 标签 id', {对象})
    
    // var tplStr = `
    // 
    // 
    // 
    //   
    //   Document
    // 
    // 
    //   

    大家好,我叫:{{ name }}

    //

    我今年 {{ age }} 岁了

    //

    我来自 {{ province }}

    //

    我喜欢:{{each hobbies}} {{ $value }} {{/each}}

    // // // ` fs.readFile('./tpl.html', function (err, data) { if (err) { return console.log('读取文件失败了') } // 默认读取到的 data 是二进制数据 // 而模板引擎的 render 方法需要接收的是字符串 // 所以我们在这里需要把 data 二进制数据转为 字符串 才可以给模板引擎使用 var ret = template.render(data.toString(), { name: 'Jack', age: 18, province: '北京市', hobbies: [ '写代码', '唱歌', '打游戏' ], title: '个人信息' }) console.log(ret) })

     

  18. 在浏览器中使用art-template

    
    
    
      
      06-在浏览器中使用art-template
    
    
      
      
      
      
    
    
    

     

  19. 在Apache案例中加入模板引擎

    var http = require('http')
    var fs = require('fs')
    var template = require('art-template')
    
    var server = http.createServer()
    
    var wwwDir = 'D:/Movie/www'
    
    server.on('request', function (req, res) {
      var url = req.url
      fs.readFile('./template-apache.html', function (err, data) {
        if (err) {
          return res.end('404 Not Found.')
        }
        // 1. 如何得到 wwwDir 目录列表中的文件名和目录名
        //    fs.readdir
        // 2. 如何将得到的文件名和目录名替换到 template.html 中
        //    2.1 在 template.html 中需要替换的位置预留一个特殊的标记(就像以前使用模板引擎的标记一样)
        //    2.2 根据 files 生成需要的 HTML 内容
        // 只要你做了这两件事儿,那这个问题就解决了
        fs.readdir(wwwDir, function (err, files) {
          if (err) {
            return res.end('Can not find www dir.')
          }
    
          // 这里只需要使用模板引擎解析替换 data 中的模板字符串就可以了
          // 数据就是 files
          // 然后去你的 template.html 文件中编写你的模板语法就可以了
          var htmlStr = template.render(data.toString(), {
            title: '哈哈',
            files: files
          })
    
          // 3. 发送解析替换过后的响应数据
          res.end(htmlStr)
        })
      })
    })
    server.listen(3000, function () {
      console.log('running...')
    })
    

     

  20. url模块

    var url = require('url')
    
    var obj = url.parse('/pinglun?name=的撒的撒&message=的撒的撒的撒', true)
    
    console.log(obj)
    console.log(obj.query)

     

  21. static-server

    var http = require('http')
    var fs = require('fs')
    var template = require('art-template')
    var path = require('path')
    
    var server = http.createServer()
    
    var wwwDir = 'D:/Movie/www'
    
    server.on('request', function (req, res) {
      var url = req.url
      // 1. 如果是文件,直接读取响应
      // 2. 如果是目录,读取渲染目录列表
      // 3. 如果目录并且有该目录中有 index.html 则直接渲染目录中的 index.html
    
      var urlPath = path.join(wwwDir, url)
    
      fs.stat(urlPath, function (err, stats) {
        if (err) {
          return res.end('404 Not Found.')
        }
        if (stats.isFile()) {
          fs.readFile(urlPath, function (err, data) {
            if (err) {
              return res.end('404 Not Found.')
            }
            res.end(data)
          })
        } else if (stats.isDirectory()) {
          var templateStr = fs.readFileSync('./static-template.html').toString()
          var files = fs.readdirSync(urlPath)
          // var data = files.map(function (item) {
          //   return {
          //     url: 
          //     name: 
          //     type: 
          //   }
          // })
          var htmlStr = template.render(templateStr, {
            files: files
          })
          res.end(htmlStr)
        }
      })
    })
    
    server.listen(3000, function () {
      console.log('running...')
    })
    

     

  22. static-template

    
    
    
      
      
      
      {{ title }}
    
    
    
      
    糟糕!Google Chrome无法解读服务器所发送的数据。请报告错误,并附上原始列表

    D:\Movie\www\ 的索引

    {{each files}} {{/each}}
    名称 大小 修改日期
    {{$value}}/ 2017/11/2 上午10:32:47

     

  23. template

    
    
    
      
      
      
      
      D:\Movie\www\ 的索引
    
    
    
      
    糟糕!Google Chrome无法解读服务器所发送的数据。请报告错误,并附上原始列表

    D:\Movie\www\ 的索引

    ^_^
    名称 大小 修改日期

     

  24. template-Apache

    html dir="ltr" lang="zh" i18n-processed="">
    
    
      
      
      
      
      {{ title }}
    
    
    
      
    糟糕!Google Chrome无法解读服务器所发送的数据。请报告错误,并附上原始列表

    D:\Movie\www\ 的索引

    {{each files}} {{/each}}
    名称 大小 修改日期
    {{$value}}/ 2017/11/2 上午10:32:47

     

  25. 服务端渲染和客户端渲染的区别
      + 客户端渲染不利于 SEO 搜索引擎优化
      + 服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的
      + 所以你会发现真正的网站既不是纯异步也不是纯服务端渲染出来的
      + 而是两者结合来做的
      + 例如京东的商品列表就采用的是服务端渲染,目的了为了 SEO 搜索引擎优化
      + 而它的商品评论列表为了用户体验,而且也不需要 SEO 优化,所以采用是客户端渲染

  26. 总结

    - Node 中的 JavaScript
      + EcmaScript
        * 变量
        * 方法
        * 数据类型
        * 内置对象
        * Array
        * Object
        * Date
        * Math
      + 模块系统
        * 在 Node 中没有全局作用域的概念
        * 在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
        * require 加载只能是执行其中的代码,文件与文件之间由于是模块作用域,所以不会有污染的问题
          - 模块完全是封闭的
          - 外部无法访问内部
          - 内部也无法访问外部
        * 模块作用域固然带来了一些好处,可以加载执行多个文件,可以完全避免变量命名冲突污染的问题
        * 但是某些情况下,模块与模块是需要进行通信的
        * 在每个模块中,都提供了一个对象:`exports`
        * 该对象默认是一个空对象
        * 你要做的就是把需要被外部访问使用的成员手动的挂载到 `exports` 接口对象中
        * 然后谁来 `require` 这个模块,谁就可以得到模块内部的 `exports` 接口对象
        * 还有其它的一些规则,具体后面讲,以及如何在项目中去使用这种编程方式,会通过后面的案例来处理
      + 核心模块
        * 核心模块是由 Node 提供的一个个的具名的模块,它们都有自己特殊的名称标识,例如
          - fs 文件操作模块
          - http 网络服务构建模块
          - os 操作系统信息模块
          - path 路径处理模块
          - 。。。。
        * 所有核心模块在使用的时候都必须手动的先使用 `require` 方法来加载,然后才可以使用,例如:
          - `var fs = require('fs')`
    - http
      + require
      + 端口号
        * ip 地址定位计算机
        * 端口号定位具体的应用程序
      + Content-Type
        * 服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
        * 不同的资源对应的 Content-Type 是不一样,具体参照:http://tool.oschina.net/commons
        * 对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
      + 通过网络发送文件
        * 发送的并不是文件,本质上来讲发送是文件的内容
        * 当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理

    - 模块系统
    - Node 中的其它的核心模块
    - 做一个小管理系统:
      + CRUD
    - Express Web 开发框架
      + `npm install express`
     

     

你可能感兴趣的:(前端开发,web前端)