35·灵魂前端工程师养成-使用nodejs实现简单nginx功能

2022-10-31 18:11:14 浏览数 (1)

  • 实现nginx静态服务器

  • 优化第一步:用户输入啥访问啥页面
  • 解决bug

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


实现nginx静态服务器


改进之前的server.js

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)

  if(path === '/'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    var accept = request.headers["accept"];
    console.log("accept:");
    console.log(accept);
    response.write(`
        <!DOCTYPE html>
        <head>
            <link rel="stylesheet" href="/x">
        </head>
        <body>
            <h1>曾老湿</h1>
            <script src="/y"></script>
        </body>
    `)
    response.end()
  } else if(path === '/x'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/css;charset=utf-8')
    response.write(`body{color: red;}`)
    response.end()
  } else if(path === '/y'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
    response.write(`console.log('这是JS内容')`)
    response.end()
  } else {
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(`你输入的路径不存在对应的内容`)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

优化第一步:用户输入啥访问啥页面

先把项目运行起来。

代码语言:javascript复制
MacBook-pro:static_server driverzeng$ node-dev server.js 8888

我们先写一个主页面

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>主页面</title>
</head>
<body>
    这个是主页:index.html
</body>
</html>

然后server.js加载页面

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)

  if(path === '/'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    var accept = request.headers["accept"];
    console.log("accept:");
    console.log(accept);
    response.write(fs.readFileSync('public/index.html'))
    response.end()
  } else {
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(`你输入的路径不存在对应的内容`)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

那我再加一个css

我还得写一个判断

style.css

代码语言:javascript复制
body{
    color:red;
}

server.js

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)

  if(path === '/'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    var accept = request.headers["accept"];
    console.log("accept:");
    console.log(accept);
    response.write(fs.readFileSync('public/index.html'))
    response.end()
  } else if(path === '/style.css'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/css;charset=utf-8')
    response.write(fs.readFileSync('public/style.css'))
    response.end()
  } else {
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(`你输入的路径不存在对应的内容`)
    response.end()
  }

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

上面的代码好鸡肋。

一个判断一个路径,要是有100个页面,我得写100个判断?

接下来我们就创建100个文件...emmm... 太多了,3个吧。

 里面的内容,就是文件名,接下来我们尝试,用户输入啥,就读取啥文件

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)


    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    var accept = request.headers["accept"];
    console.log("accept:");
    console.log(accept);
    const filePath =  path
    response.write(fs.readFileSync(`public${filePath}`))
    response.end()

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

实现了,写啥就读取啥。

但是....注意啦,如果写一个不存在的路径会怎么样?

额...我擦嘞,服务直接挂了。

解决bug


不存在的页面不让服务挂

我们使用try ,catch一下,抓一下错误。

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)


    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    var accept = request.headers["accept"];
    console.log("accept:");
    console.log(accept);
    const filePath = path
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

不存在就报错,存在就正常显示页面。


访问/即访问默认主页

但是....emm... mmp... 如果访问/也是不存在

如何是好?继续解决bug

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)


    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    var accept = request.headers["accept"];
    console.log("accept:");
    console.log(accept);
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

呦西,但是 还有一个问题,就是代码中 Content-Type 永远都是text/html

这样不就智障了吗?我要解析解析一个css文件,你按照html来解析?


根据访问文件内容选择解析

获取请求路径的后缀。

代码语言:javascript复制
console.log(filePath.lastIndexOf('.'))

可以看到当访问a.html的时候,第2个是'.' 当访问style.css的时候,第6个是'.'

我们就可以根据这个'.'来判断文件的后缀,然后使用对应的解析

代码语言:javascript复制
const index = filePath.lastIndexOf('.')
const backend = filePath.substring(index)
console.log(backend)

打印一下,后缀是啥,获取到没有。

使用hash表数据结构,来把后缀替换到Content-Type中

代码语言:javascript复制
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
  console.log('请指定端口号好不啦?nnode server.js 8888 这样不会吗?')
  process.exit(1)
}

var server = http.createServer(function(request, response){
  var parsedUrl = url.parse(request.url, true)
  var pathWithQuery = request.url 
  var queryString = ''
  if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
  var path = parsedUrl.pathname
  var query = parsedUrl.query
  var method = request.method

  /******** 从这里开始看,上面不要看 ************/

  console.log('有个傻子发请求过来啦!路径(带查询参数)为:'   pathWithQuery)

    response.statusCode = 200
    const filePath = path === '/' ? '/index.html' : path    // 默认首页
    const index = filePath.lastIndexOf('.')
    const backend = filePath.substring(index)
    const fileTypes = {
        '.html':'text/html',
        '.css':'text/css',
        '.js':'text/javascript',
        '.json':'application/json',
        '.png':'image/png',
        '.jpg':'image/jpeg',
        '.jpeg':'image/jpeg',
        '.gif':'image/gif'
    }
    response.setHeader('Content-Type', `${fileTypes[backend] || 'text/html'};charset=utf-8`)
    console.log(backend)
    let content
    try {
        content =  fs.readFileSync(`public${filePath}`)
    } catch (error) {
        content = '文件:'  filePath '不存在啊,大兄弟,你这是要上天啊?'
        response.statusCode = 404
    }
    response.write(content)
    response.end()

  /******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 '   port   ' 成功n请用在空中转体720度然后用电饭煲打开 http://localhost:'   port)

尝试放入图片


引用文件

代码语言:javascript复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>主页面</title>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div>
        <img src="./naruto.jpeg" alt="">
        <script src="./c.js"></script>
    </div>
    这个是主页:index.html
</body>
</html>

0 人点赞