前端学习 node 快速入门 系列 —— 简易版 Apache

其他章节请看:

前端学习 node 快速入门 系列

简易版 Apache

我们用 node 来实现一个简易版的 Apache:提供静态资源访问的能力

实现

直接上代码。

- demo
    - static            // 静态资源文件夹
        - index.html    // 主页
        - 1.jpg         
        - 1.css
        - 1.js
    - index.js          // 入口文件

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="1.css">
</head>
<body>
   <p>欢迎来到首页</p>
   <img src="1.jpg" alt="">
   <section></section>
   <script src='1.js'></script>
</body>
</html>

1.js 和 1.css:

document.querySelector('section').innerHTML = '我来自js' // js

body{color:red} // css

index.js(入口文件):

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

const requestListener = (req, res) => {
    const url = req.url
    // 如果url是 '/',则返回主页
    if(url === '/'){
        fs.readFile('./static/index.html', (err, data) => {
            if (err) throw err;
            res.end(data)
        });
        return
    }

    // 如果url不是 '/',则返回资源(找不到资源则报 404)
    fs.readFile('./static/' + url, (err, data) => {
        if (err) {
            res.writeHead(404, {'Content-type':'text/html;charset=utf8'})
            res.end('没有找到对应的资源')
        }
        res.end(data)
    })
}

server.on('request', requestListener)
server.listen('3000', () => {
    console.log('服务器已启动')
})

启动服务器:

$ node index

检验服务器是否能提供静态资源访问的能力。

1. 浏览器输入 //localhost:3000/1.css

页面显示:body{color:red}

2. 浏览器输入 //localhost:3000/1.js

页面显示:document.querySelector('section').innerHTML = '鎴戞潵鑷猨s'(未指定编码,所以中文乱码。不碍事)

3. 浏览器输入 //localhost:3000/1.jpg
页面显示:1.jpg(正常显示图片)

3 种静态资源都能正常响应。

访问主页:

浏览器输入://localhost:3000/index.html 或 //localhost:3000/

页面显示:
欢迎来到首页
图片
我来自js

主页和其中的图片、css 以及 js 配合的非常完美。

:中文乱码的问题没有出现。因为我们在 html 页面中 使用了 <meta charset="utf-8"> 来指定编码。

通常访问不存在的资源会返回 404。请看:

浏览器输入://localhost:3000/2.css

页面显示:
没有找到对应的资源

扩展

至此,我们的简易版 apache 其实已经大功告成。在此基础之上,我们再扩展一下。

我的服务器我做主

理解这一点很重要:这个服务器完全由我们做主

现在所有的请求都会进入 requestListener() 方法,如果 url 是 ‘/’,服务器就返回主页(index.html),否则就去 static 文件夹中读取相应的资源,如果没有找到对应的资源,就做 404 的处理。假如 requestListener() 是一个空方法,则说明我们的服务器不提供任何服务。

所有的请求都是 url

不要把 //localhost:3000/1.css 中的 1.css 当成文件路径,而要当成 url,因为所有的请求都是 url。请看示例:

const requestListener = (req, res) => {
    ...
    if(url.endsWith('.myCss')){
        url = url.replace('.myCss', '.css') // url 得声明成 let
    }
    fs.readFile('./static/' + url, (err, data) => { // {1}
        ...
    })
}

在 index.js 的 fs.readFile('./static/'(行{1}) 上面增加三行代码。

浏览器输入 //localhost:3000/1.myCss

页面显示:body{color:red}

现在给服务器发送请求 //localhost:3000/1.myCss,服务器也会返回 1.css 文件的内容。有些网站的 url 设计的非常优雅。请看:

//product.dangdang.com/29200520.html

// 更优雅
//www.douban.com/group/topic/214827461/

重定向

未登录的状态去访问页面,通常会被重定向到首页。我们来模拟一下:

if(url.endsWith('.myCss')){
    url = url.replace('.myCss', '.css') 
    res.writeHead(302, {'Location':'/'}) // {1}
    // 行{1} 等价于下面两行
    // res.statusCode = '302'
    // res.setHeader('Location', '/') 
    
}

在 index.js 中增加 res.writeHead(302, {'Location':'/'})(行{1}),浏览器输入 //localhost:3000/1.myCss,页面会重定向到主页。

:没有后端开发经验的学习 node 会比较吃力。比如重定向,我们想到的可能是通过调用一个重定向的方法来实现,而 node 写起来更底层。

302 是临时重定向。301 是永久重定向。请看示例:

// 临时重定向
Request URL: //localhost:3000/1.myCss
Request Method: GET
Status Code: 302 Found

Request URL: //localhost:3000/1.myCss
Request Method: GET
Status Code: 302 Found

// 永久重定向
Request URL: //localhost:3000/1.myCss
Request Method: GET
Status Code: 301 Moved Permanently

Request URL: //localhost:3000/1.myCss
Request Method: GET
Status Code: 301 Moved Permanently (from disk cache) // {1}

临时重定向,浏览器每次都会去服务器那里;而永久重定向,第二次就不会去服务器那里,而是直接在浏览器端重定向过去(行{1})

自动重启服务

每次修改入口文件,都需要重新启动服务器(执行 node index),非常麻烦。

可以通过 nodemon 来帮助我们自动重启服务。

// 全局安装 nodemon。
$ npm install --global nodemon

// 一定要全局安装 nodemon。否则执行 nodemon -v 会报错。
$ nodemon -v

// 运行入口文件。
$ nodemon index // {1}

使用 nodemon 非常简单。通过 npm 全局安装后,用 nodemon 代替 node(行{1})运行入口文件即可。

:笔者还尝试了 supervisor,感觉没有 nodemon 好用。比如我输入 let a = (处在一个语法错误的状态)然后保存,supervisor 会退出服务,而 nodemon 只是报错,仍会继续监听。

其他章节请看:

前端学习 node 快速入门 系列

Tags: