NodeJs 笔记(二)

NodeJs 笔记(二)

1.1 初步实现Apache功能

var http = require('http')
1. 创建Server
var server = http.createServer()
2. 监听Server的request请求,设置请求处理函数
//请求、处理、响应。一个请求对应一个响应
var wwwDir = 'D:/Movie/www'//定义一个路径

server.on('request',function(req,res){
    var url = req.url
    if (url == '/') {
        fs.readFile(wwwDir + '/index.html',function(err,data){
            if(err){
            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...')
})

1.2 Apache-文件夹生成目录列表

  • 获取某个文件夹下的所有的文件名和目录名,可以使用fs.readdir(路径,function(err,files))
  • template模板html中添加一个特殊标记,根据这个特殊标记,我们可以在JS文件中替换这个标记(用我们想要显示的内容替换)
  • 如何替换?利用readdir形参files去遍历files.forEach(item),给获取到的每一项item。然后利用${}来引用变量
1. 如何得到 wwwDir 目录列表中的文件名和目录名
       fs.readdir
2. 如何将得到的文件名和目录名替换到 template.html 中
2.1 在 template.html 中需要替换的位置预留一个特殊的标记(就像以前使用模板引擎的标记一样)
2.2 根据 files 生成需要的 HTML 内容
    fs.readdir('H:\www', function (err, files) {
      if (err) {
        return res.end('Can not find www dir.')
      }

2.1 生成需要替换的内容
      var content = ''
      files.forEach(function (item) {
        // 在 EcmaScript 6 的 ` 字符串中,可以使用 ${} 来引用变量
        content += `
          <tr>
            <td data-value="apple/"><a class="icon dir" href="/D:/Movie/www/apple/">${item}/</a></td>
            <td class="detailsColumn" data-value="0"></td>
            <td class="detailsColumn" data-value="1509589967">2017/11/2 上午10:32:47</td>
          </tr>
        `
      })

2.3 替换
      data = data.toString()
      data = data.replace('^_^', content)

3. 发送解析替换过后的响应数据
      res.end(data)
    })

2.1 模板引擎

  1. art-template安装npm install art-template
  2. 在需要使用的文件模块中加载art-template只需要使用require方法加载就可以了:require(‘art-template’)参数中的 art-template,就是你下载的包的名字,也就是说你isntall的名字是什么,则你 require 中的就是什么
  3. 查文档,使用模板引擎的API
  4. 注意:模板引擎只关心挂载的html中{{引用对象的某个属性}},其他有错误都不关心。
  • 总结:模版引擎的使用,先require加载它,再通过fs.readFile去读取某一个文件,在读操作中写入template.render(data.toString(),{数据对象})。
  • 作用:读取的html文件中可以通过{{}}来引用数据对象中的数据
var template = require('art-template')
var fs = require('fs')

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)
}
上边例子调用这个HTML,替换里边的数据内容:
tpl.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
    <p>大家好,我叫:{{ name }}</p>
    <p>我今年 {{ age }} 岁了</p>
    <h1>我来自 {{ province }}</h1>
    <p>我喜欢:{{each hobbies}} {{ $value }} {{/each}}</p>
</body>
</html>
  • 例子中使用:template.render(‘要替换的目标’,{包含要替换内容的对象})。如果使用fs.readFile,则第一个参数为形参data.toString()

2.2 服务端渲染页面

  • 服务端读取模版HTML文件,然后利用readdir(‘文件夹路径’,function(err,files){})获取files数据(该数据的值files.value为文件名)。使用
    template.render(data.toString(),{渲染的数据})。
  • 注:其中data是readFile回调函数里的第二个参数,所以要写在readFile中。
fs.readFile('读取的文件',function(err,data){
    嵌套fs.readdir读取文件夹中的文件名和目录名
    fs.readdir('文件夹路径',function(err,files){
        再次嵌套template.render用于渲染模版HTML
        template.render(data.toString(),{
            渲染的数据
            title: '哈哈',
            files: files
        })
    })
})
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...')
})

2.3 总结

  1. 客户端渲染(至少请求两次)
  • 输入网址,浏览器DNS解析出服务器的IP地址,发送响应请求。服务器发送回来一个字符串(包含完整HTML页面结构),浏览器解析字符串。
  • 解析到ajax会异步再次发送请求,响应到接口数据,用来渲染模板引擎(数据动态渲染,页面无需卸载,例如:电商的商品评论)。
此处的字符串(完整的HTML页面结构)内容:
<html>
    <head></head>
    <script type='tpl'>
    模板字符串(你要显示的模板,会引用{{数据}})
    </script>
    <script>
    $.ajax({
    服务器解析到这会自动再次发送数据请求
    })
    </script>
</html>
  1. 服务端渲染(至少一次请求)
  • 服务器中响应的时候是页面+数据渲染完成后再发送给浏览器。
  • 使用template.render(模板字符串,{解析替换对象})和response.end(发送渲染后的字符串)来完成渲染。
  • 其中模版字符串是通过fs.readFile中的回调函数的第二个参数data,通过toString()后获得的。
  • 需要重新加载页面,例如:电商的商品展示
这个模板字符串:
<html>
<head></head>
<body>
    <h1>hello{{name}}</h1>
</body>
</html>
  1. 总结:
- 客户端渲染,不利于SEO(搜索引擎优化)
- 服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的。
- 真正的网站是两者结合起来的。例如京东的商品列表,是服务端渲染(有利于搜索引擎搜索到),而评论区则采用客户端渲染(动态加载数据,响应更快)

2.3 处理网站中的静态资源

  • 利用http创建的Server,再Server.on和Server.listen。都可以通过链式编程,甚至都不用去定义Server。
var http = require('http')
http
    .createServer(function(req,res){
        //写原先server.on的内容
    })
    .listen(3000,function(){
        console.log('Server is running')
    })
  • 为了让目录结构保持统一清晰,所以我们约定,把所有的HTML文件都放到views(视图)目录中我们为了方便的统一处理这些静态资源,所以我们约定把所有的静态资源都存放在public目录中哪些资源能被用户访问,哪些资源不能被用户访问,我现在可以通过代码来进行非常灵活的控制
var fs = require('fs')
var http = require('http')
var url = require('url')
var template = require('art-template')

var comments = [
    {
      name: '张三',
      message: '今天天气不错!',
      dateTime: '2015-10-16'
    },
    {
      name: '张三2',
      message: '今天天气不错!',
      dateTime: '2015-10-16'
    },
    {
      name: '张三3',
      message: '今天天气不错!',
      dateTime: '2015-10-16'
    },
    {
      name: '张三4',
      message: '今天天气不错!',
      dateTime: '2015-10-16'
    },
    {
      name: '张三5',
      message: '今天天气不错!',
      dateTime: '2015-10-16'
    }
  ]
  • 上半部分代码:主要是加载一些核心插件和定义数据对象。
  • 下半部分代码
    • 使用到了url核心插件的url.parse()方法将路径解析为一个方便操作的对象,第二个参数为 true 表示直接将查询字符串转为一个对象(通过 query 属性来访问提交的数据)。
    url.parse('网址',ture)返回的内容:
    URL:{
    protocol: 'http:',
    host:'127.0.0.1:3000',
    port:'3000',
    hostname:'127.0.0.1',
    query:'/pinglun?name=%E7%9AXXXX&message=%3XXX',  
    //注意:第二个参数为true时,query会解析为
    query:{name:'何勤',message:'套猴子'}
    pathname: '/pinglun',
    path: '/pinglun?namexxxx',
    herf: 'http://127....'
    }
    
    • 只需要判定请求路径是/pinglun的时候,就认为提交表单的请求过来 。在该路径下,获取表单提交的内容,将内容放进comments数据对象,并重新定位回到主页。
    else if (pathname == '/pinglun'){
      两件事:
          1. 获取提交过来的内容,并把它放入comments对象中。
              var comment = parseObj.query
              comment.dateTime = '2017-11-2 17:11:22'
              comments.unshift(comment)
          2. 修改状态码为302,让其重新定位到首页
              res.statusCode = 302
              res.setHeader('Location', '/')
              res.end()
          }
    
    • 这段代码将public文件夹里的文件设置为开放状态,只要输入正确的路径就能访问到public中的所有文件
      if(pathname.indexOf('/public/') === 0){
          fs.readFile('.' + pathname, function(err,data){
              if (err) {
                  return res.end('404 Not Found.')
              } else {
                  res.end(data)
              }
          })
      }
    
http
    .createServer(function(req,res){
        url核心插件的parse方法将路径解析为一个方便操作的对象
        var parseObj = url.parse(req.url, true)
        var pathname = parseObj.pathname
        if (pathname == '/'){
            fs.readFile('./views/index.html', function(err,data){
                if (err) {
                    return res.end('404 Not Found.')
                } else {
                    var htmlStr = template.render(data.toString(), {
                        comments: comments
                    })
                }
                res.end(htmlStr)
            })
        } else if (pathname == '/post') {
            fs.readFile('./views/post.html', function(err,data){
                if (err) {
                    return res.end('404 Not Found.')
                } else {
                    res.end(data)
                }
            })
        } else if (pathname.indexOf('/public/') === 0){
            fs.readFile('.' + pathname, function(err,data){
                if (err) {
                    return res.end('404 Not Found.')
                } else {
                    res.end(data)
                }
            })
        } else if (pathname == '/pinglun'){
        对于我们来讲,其实只需要判定,如果你的请求路径是/pinglun的时候,那我就认为你提交表单的请求过来
        然后做两件事:
        1. 获取提交过来的内容,并把它放入comments对象中。
            var comment = parseObj.query
            comment.dateTime = '2017-11-2 17:11:22'
            comments.unshift(comment)
        2. 修改状态码为302,让其重新定位到首页
            res.statusCode = 302
            res.setHeader('Location', '/')
            res.end()
        }
    })
    .listen(3000,function(){
        console.log('running')
    })
  • 下边为post.html,是“发表留言”的页面,主要了解表单如何提交到服务器端的。<form action="/pinglun" method="get"> form中action的值就是请求的url地址
  • 工作原理:当我们点提交的时候,网址会跳到action的值(即路径)127.0.0.1:3000/pinglun?name=你输入的姓名&message=你留言的内容,因此,我们可以通过判别路径是否为‘/pinglun’,再用parseObj对象.query获取到name和message
post:
 <div class="comments container">
    <!-- 
      以前表单是如何提交的?
      表单中需要提交的表单控件元素必须具有 name 属性
      表单提交分为:
        1. 默认的提交行为
        2. 表单异步提交

        action 就是表单提交的地址,说白了就是请求的 url 地址
        method 请求方法
            get
            post
     -->
    <form action="/pinglun" method="get">
      <div class="form-group">
        <label for="input_name">你的大名</label>
        <input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="请写入你的姓名">
      </div>
      <div class="form-group">
        <label for="textarea_message">留言内容</label>
        <textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea>
      </div>
      <button type="submit" class="btn btn-default">发表</button>
    </form>
  </div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值