Nodejs 构建http服务

TCP 和 UDP 都属于网络传输层协议,如果要构建高效的网络应用,就应该从传输层进行着手。但是对于经典的浏览器网页和服务端通信场景,如果单纯的使用更底层的传输层协议则会变得麻烦。

所以对于经典的B(Browser)S(Server)通信,基于传输层之上专门制定了更上一层的通信协议:HTTP,用于浏览器和服务端进行通信。由于 HTTP 协议本身并不考虑数据如何传输及其他细节问题,所以属于应用层协议。

Node 提供了基本的 http 和 https 模块用于 HTTP 和 HTTPS 的封装。

const http = require('http')
const server = http.createServer()

Server 实例

API说明
Event:‘close’服务关闭时触发
Event:‘request’收到请求消息时触发
server.close()关闭服务
server.listening获取服务状态

请求对象

API说明
request.method请求方法
request.url请求路径
request.headers请求头
request.httpVersion请求HTTP协议版本

响应对象

API说明
response.end()结束响应
response.setHeader(name, value)设置响应头
response.removeHeader(name, value)删除响应头
response.statusCode设置响应状态码
response.statusMessage设置响应状态短语
response.write()写入响应数据
response.writeHead()写入响应头

使用 Node 构建 http 服务

Hello World

const http = require('http')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('Hello World\n')
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

根据不同 url 处理不同请求

const http = require('http')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  const url = req.url
  if (url === '/') {
    res.end('Hello World!')
  } else if (url === '/a') {
    res.end('Hello a!')
  } else if (url === '/b') {
    res.end('Hello b!')
  } else {
    res.statusCode = 404
    res.end('404 Not Found.')
  }
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

响应 HTML 内容

const http = require('http')
const fs = require('fs')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  fs.readFile('./index.html', (err, data) => {
    if (err) {
      throw err
    }
    res.statusCode = 200
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    res.end(data)
  })

//   res.end(`
// <h1>Hello World!</h1>
// <p>你好,世界!</p>
//   `)
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

处理页面中的静态资源

const http = require('http')
const fs = require('fs')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  const url = req.url
  if (url === '/') {
    fs.readFile('./index.html', (err, data) => {
      if (err) {
        throw err
      }
      res.statusCode = 200
      res.setHeader('Content-Type', 'text/html; charset=utf-8')
      res.end(data)
    })
  } else if (url === '/assets/css/main.css') {
    fs.readFile('./assets/css/main.css', (err, data) => {
      if (err) {
        throw err
      }
      res.statusCode = 200
      res.setHeader('Content-Type', 'text/css; charset=utf-8')
      res.end(data)
    })
  } else if (url === '/assets/js/main.js') {
    fs.readFile('./assets/js/main.js', (err, data) => {
      if (err) {
        throw err
      }
      res.statusCode = 200
      res.setHeader('Content-Type', 'text/javascript; charset=utf-8')
      res.end(data)
    })
  } else {
    res.statusCode = 404
    res.setHeader('Content-Type', 'text/plain; charset=utf-8')
    res.end('404 Not Found.')
  }
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

统一处理页面中的静态资源

const http = require('http')
const fs = require('fs')
const mime = require('mime')
const path = require('path')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  const url = req.url
  if (url === '/') {
    fs.readFile('./index.html', (err, data) => {
      if (err) {
        throw err
      }
      res.statusCode = 200
      res.setHeader('Content-Type', 'text/html; charset=utf-8')
      res.end(data)
    })
  } else if (url.startsWith('/assets/')) {
    // /assets/js/main.js
    fs.readFile(`.${url}`, (err, data) => {
      if (err) {
        res.statusCode = 404
        res.setHeader('Content-Type', 'text/plain; charset=utf-8')
        res.end('404 Not Found.')
      }
      const contentType = mime.getType(path.extname(url))
      res.statusCode = 200
      res.setHeader('Content-Type', contentType)
      res.end(data)
    })
  } else {
    res.statusCode = 404
    res.setHeader('Content-Type', 'text/plain; charset=utf-8')
    res.end('404 Not Found.')
  }
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

使用模板引擎处理动态页面

假如我们有一份数据 todos 需要展示到页面中

const todos = [
  { title: '吃饭', completed: false },
  { title: '睡觉', completed: true },
  { title: '打豆豆', completed: false }  
]

如何将一组数据列表展示到一个页面中,最简单的方式就是字符串替换,但是如果有不止一份数据需要展示到页面中的时候就会变得非常麻烦,所以前人将此种方式整合规则之后开发了我们常见的模板引擎。

例如我们经常在网页源码中看到下面这样一段代码

<ul>
  <% todos.forEach(function (item) { %>
  <li><%= item.title %></li>
  <% }) %>
</ul>

或者是

<ul>
  {{ each todos }}
  <li>{{ $value.title }}</li>
  {{ /each }}
</ul>

无论如何,我们看到的这些语法都在模板引擎所指定的一些规则,目的就是让我们可以非常方便的在网页中进行字符串替换以达到动态网页的效果。

在 Node 中,有很多优秀的模板引擎,它们大抵相同,但都各有特点

基本使用

const template = require('art-template')

// const ret = template.render('Hello {{ message }}', {
//   message: 'World'
// })

const ret = template.render(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
  <h1>Hello {{ message }}</h1>
  <ul>
    {{ each todos }}
    <li>{{ $value.title }} <input type="checkbox" {{ $value.completed ? 'checked' : '' }} /></li>
    {{ /each }}
  </ul>
</body>
</html>
`, {
  message: 'World',
  todos: [
    { title: '吃饭', completed: false },
    { title: '睡觉', completed: true },
    { title: '打豆豆', completed: false }
  ]
})

console.log(ret)

结合 http 服务渲染页面

const http = require('http')
const template = require('art-template')
const fs = require('fs')

const hostname = '127.0.0.1'
const port = 3000

const server = http.createServer((req, res) => {
  const url = req.url
  if (url === '/') {
    fs.readFile('./index2.html', (err, data) => {
      if (err) {
        throw err
      }
      const htmlStr = template.render(data.toString(), {
        message: '程序员',
        todos: [
          { title: '吃饭', completed: true },
          { title: '睡觉', completed: true },
          { title: '打豆豆', completed: false }
        ]
      })
      res.statusCode = 200
      res.setHeader('Content-Type', 'text/html')
      res.end(htmlStr)
    })
  }
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

第三方 HTTP 服务框架

更多优秀的第三方资源 awesome node.js

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值