黑马 Node.js起步 笔记

这篇博客详细介绍了Node.js的起步,包括创建简单程序、HTTP服务、响应内容类型、模块化、实现Apache功能和留言版功能。重点讲解了Node.js中的JavaScript、响应Content-Type、Express框架的使用,以及如何处理文件和目录。此外,还涉及到了npm管理和文件操作路径。博客提供了丰富的示例代码,帮助读者深入理解Node.js开发。
摘要由CSDN通过智能技术生成

Node.js 起步

  • Node.js 是一个服务端的语言

  • 服务端的语言与前端不一样,前端只有H5,CSS,JS以及以他为基础的其他语言,但是服务端有很多语言都可以实现H5这样最基础的功能,他们之间是并列关系,没有依赖,例如Java,PHP,Python,Ruby,.Net,Nodejs

  • 使用Node.js的原因是可以使用js语言,对前端友好

  • Node.js是什么

    1. 是一个JS运行时环境(Runtime lib)而不是一个库,不是一个框架,不是一个语言,(可以理解他是和一个浏览器一样的东西,但是有点不一样)

      • 浏览器中的JS是什么

        • 基础语法 ECMAScript
        • DOM
        • BOM
      • Node.js中的JS是什么

        • 没有BOM,DOM(因为服务端不处理页面)
        • 基础语法 ECMAScript
        • 服务器级别的API(文件读写,网络服务构建,http服务…)
    2. 是一个事件驱动非阻塞IO模型(异步),高效轻量

    3. 使用npm生态系统,也是最大的开源生态系统

    4. 构建在v8引擎是上的

  • Nodejs可以做什么

    • Web后台
    • 命令行工具(例如: hexo,gulp…)
    • 接口服务器

简单程序

直接创建js文件写就可以了,不需要依赖html文件,之后使用node xx.js执行文件

写出hello world

var foo='hello world'
console.log(foo);

之后尝试服务端的文件读写,注意浏览器的HTML是不支持文件读写的

// fs是file-system的缩写,就是文件系统的意思 
// 在Node中如果想要使用文件io那必须引入fs这个模块
// fs模块为所有的文本操作提供了相关的api
var fs=require("fs");

// 其中的readFile是用来读取文件的,第一个是地址,第二个是回调函数,回调接受两个参数,error和data
//    - error表示文件读取是否有错误,有错是error对象,没错的null
//    - data是读取到的数据,有错是null,没错是16进制结果,需要toString才能看
fs.readFile("./test",function(error,data){
   
    if(!error)
        console.log(data.toString());
    else
        console.log("ERROR!!\n"+error)
});

// tst文件不存在
fs.readFile("./tst",function(error,data){
   
    if(!error)
        console.log(data.toString());
    else
        console.log("ERROR!!\n"+error)
});

// 参数为 路径 内容 回调函数(接受error)
fs.writeFile("./out","测试文本",function(error){
   
    if(error)
        console.log("文件写入失败");
})

// 文件名有非法字符 写入失败
fs.writeFile("./o/*-ut","测试文本",function(error){
   
    if(error)
        console.log("文件写入失败"+error);
})

最简单的http服务

需要核心模块http

// 加载http核心模块
var http = require('http');

// 使用http.creatServer创建一个web服务器
// 返回一个server实例
var server = http.createServer();

// 发请求 收请求 处理请求 发生相应

// 注册request请求时间,受到request请求之后就会执行回调函数
server.on("request",function(){
   
    console.log("受到客户端请求");
})

// 绑定3000端口,启动服务器
server.listen(3000,function(){
   
    console.log("服务器启动成功");
});

响应请求

var http = require('http');

var server = http.createServer();

//request的回调函数要接受两个函数
//    - Request 请求对象
//      获取客户端的请求信息,例如路径
//    - Reponse 相应对象
//      响应对象可以用来给客户端发送相应消息

server.on("request",function(request,response){
   
    // 输出访问路径的地址 127.0.0.1:3000/a 得到的是/a
    console.log("受到客户端请求, 请求路径是"+request.url);
    // response.write可以用来发送相应
    // write可以用多次但是一定要用end来结束否则客户端会一直接受,end之后不能再发请求
    response.write("hello");
    response.write("123456");
    response.end();
})

server.listen(3000,function(){
   
    console.log("服务器启动成功");
});

p.s. 浏览器在访问的时候会有一个默认请求favicon.ico,获取图标不用管

不同路径不同请求

var http = require('http');

var server = http.createServer();

server.on("request",function(request,response){
   
    var value=""
    var obj=[{
   
        title:123,
        name:456,
    },{
   
        title:45,
        name:45,
    },{
   
        title:23,
        name:4,
    }];
    switch (request.url) {
   
        case "/":value="index";break;
        case "/log":value="登陆";break;
        case "/reg":value="注册";break;
        default:value="错误";break;
    }
    response.write("收到请求,进入"+value+"页面");
    // 注意相应内容只能是二进制文件或者是字符串,不支持JSON对象,数组....
    response.write(JSON.stringify(obj));
    response.end();
})

server.listen(3000,function(){
   
    console.log("服务器启动成功");
});

获取服务器端口与客户端端口号

server.on("request",function(request,response){
   
    console.log("服务端口:"+request.socket.localPort+"客户端端口"+request.socket.remotePort);
}

中文乱码的问题

node服务器默认是发送utf8的数据,但是浏览器不知道,于是按照操作系统默认编码解析,于是服务器要告诉浏览器是用的utf8,方法是

rep.setHeader('Content-Type',"text/plain;charset=utf-8")

Node中的js

  • ECMAScript
    • 没有DOM,BOM
  • 核心模块
    • Node为JS提供了服务器级别的API,他们都被包装到了一个具名的核心模块中了,例如fs文件系统,httphttp模块,path路径模块,os操作系统模块
    • 以后一说他是核心模块就直接var XXX=require("YY")XX命名不强制最好与YY相同
  • 第三方模块
  • 自定义模块

简单模块化

两个方法: require用来加载export用来导出
require 是一个方法
他的作用是加载模块的
模块有三种
- 具名的核心模块,例如 fs, http
- 用户自己编写的文件模块(require的时候./不能省略否则就成核心模块了,可以不写.js)

1.js

console.log("开始执行1");
var mod2=require("./2.js")
console.log("结束执行1");

2.js

console.log("外部文件加载好了")
  • 在node中,没有全局作用域,只有模块作用域,也就是变量只能在本文件内部使用
  • require之后会自动执行内部的代码然后获取文件的接口对象
  • 如果不仅想要执行子模块代码,还想使用接口对象中的内容需要
    1. 将方法实例化成本模块中的一个对象
    2. 将需要暴露的对象作为接口对象导出

1.js 续

console.log(mod2.foo)
console.log(mod2.plus(1,1.2));

2.js 续

exports.foo="hello";
exports.plus=function(a,b){
   
    return a+b;
}

响应内容类型Content-Type

rep.setHeader("Content-Type","text/plain;charset=utf-8");

注意双引号是引到哪里

对与HTML代码的设置

以上是针对纯文本的,尝试以下设置

var http=require("http");
var server=http.createServer();
server.on("request",function(req,rep){
   
    rep.write("<p>123<a href="javascript:;">456</a></p>");
    rep.write("<p>中文<a href="javascript:;">测试</a></p>");
    rep.end();
})
server.listen(3000,function(){
   
    console.log("node start...");
})
  • 发现123456显示正常,并没有显示标签,可以看到network受到的包是有标签的,是浏览器进行了渲染导致用户看不到标签
  • 发现中文显示失败,这是因为没有设置utf-8

尝试设置

var http=require("http");
var server=http.createServer();
server.on("request",function(req,rep){
   
    rep.setHeader("Content-Type","text/plain;charset=utf-8");
    rep.write("<p>123<a href="javascript:;">456</a></p>");
    rep.write("<p>中文<a href="javascript:;">测试</a></p>");
    rep.end();
})
server.listen(3000,function(){
   
    console.log("node start...");
})

发现 中文显示正常,但是标签被显示了,这是因为node明确的告诉了浏览器这是文本,不让浏览器解析,解决方法是把plain改为html

var http=require("http");
var server=http.createServer();
server.on("request",function(req,rep){
   
    rep.setHeader("Content-Type","text/html;charset=utf-8");
    rep.write("<p>123<a href="javascript:;">456</a></p>");
    rep.write("<p>中文<a href="javascript:;">测试</a></p>");
    rep.end();
})
server.listen(3000,function(){
   
    console.log("node start...");
})

中文与标签正常显示

注意每一次发送响应只能设置一次Content-Type,每次end后不得再次write

其他类型的Content-Type

  • html文件
var http=require("http");
var fs=require("fs");
const {
    report } = require("process");
var server=http.createServer();

server.on("request",function(req,rop){
   
    rop.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readFile("./index.html",function(error,data){
   
        if(error)
            rop.write("ERROR");
        else
            rop.write(data);
    });
    rop.write("123");
    rop.end();
})

server.listen(3000,function(){
   
    console.log("working...");
})

注意,有问题,只能看到123因为回调函数是异步模块,当读取到回调函数的时候会将他放到事件队列等待,执行主线程,于是就读取了rop.write("123");然后马上就是rop.end等主代码结束,才打开时间队列循环,发送请求,但是迟了,早就end了!!!,如何验证??换成如下代码,等读到setTimeout(rop.end,10000);开始分线程计时,读取事件队列,之后10s后发送end,源文件显示了,同时可以看到是先有123后有HTML代码!!

server.on("request",function(req,rop){
    
    rop.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readFile("./index.html",function(error,data){
   
        if(error)
            rop.write("ERROR");
        else
            rop.write(data);
    });
    rop.write("123");
    setTimeout(rop.end,10000);
})

所以,最好的办法是

var http=require("http");
var fs=require("fs");
const {
    report } = require("process");
var server=http.createServer();

server.on("request",function(req,rop){
   
    rop.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readFile("./index.html",function(error,data){
   
        if(error)
            rop.end("ERROR");
        else
            rop.end(data);
    });
})

server.listen(3000,function(){
   
    console.log("working...");
})

终止必须在异步模块里面

  • png
// png 图片就不用指定编码了 一般只有字符数据指定编码
rop.setHeader("Content-Type","image/png");
    fs.readFile("./3.png",function(error,data){
   
        if(error)
            rop.end("ERROR");
        else
            rop.end(data);
        
    });
  • 其他类型的Content-Type
    • 媒体格式
      • text/html : HTML格式
      • text/plain :纯文本格式
      • text/xml : XML格式
      • image/gif :gif图片格式
      • image/jpeg :jpg图片格式
      • image/png:png图片格式
    • 以application开头的媒体格式类型:
      • application/xhtml+xml :XHTML格式
      • application/xml : XML数据格式
      • application/atom+xml :Atom XML聚合格式
      • application/json : JSON数据格式
      • application/pdf :pdf格式
      • application/msword : Word文档格式
      • application/octet-stream : 二进制流数据(如常见的文件下载)
      • application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
    • 更多(https://tool.oschina.net/commons)[https://tool.oschina.net/commons]

实现一些apach功能

实现目录浏览功能

  • 输入地址访问部分文件
var http=require("http");
var fs=require("fs");
var server=http.createServer();

server.on("request",function(req,res){
   
    rep.setHeader("Content-Type","text/plain;charset=utf-8")
    var reg=new RegExp("^\/file\/","i");
    if(reg.test(req.url)){
   
        fs.readFile(req.url.replace(reg,".\/"),function(error,data){
   
            if(error){
   
                res.end("ERROR REQ");
                console.log(error);
            }else{
   
                res.end(data);
            }
        });
    }else{
   
        res.end("welcom");
    }
});

server.listen(3000,function(){
    
    console.log("working...");
})

输入网址访问文件目录

需求1 显示指定文件夹下文件目录
需要使用文件目录那一定是fs模块,查API得到fs.readdir("PATH",function(error,files))files是文件名数组(注意两个d都没大写)

var fs=require("fs");

fs.readdir("../01/",function(error,files){
   
    if(error)
        console.log(error);
    else
        console.log(files);
});

需求2 动态显示
当然我们可以使用字符串替换暴力实现

<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
    <meta charset="utf-8">
    <style>
        h1 {
     
            border-bottom: 1px solid #c0c0c0;
            margin-bottom: 10px;
            padding-bottom: 10px;
            white-space: nowrap;
        }
        table {
     
            border-collapse: collapse;
        }
        th {
     
            cursor: pointer;
        }
        td.detailsColumn {
     
            -webkit-padding-start: 2em;
            text-align: end;
            white-space: nowrap;
        }
        a.icon {
     
            -webkit-padding-start: 1.5em;
            text-decoration: none;
            user-select: auto;
        }
        a.icon:hover {
     
            text-decoration: underline;
        }
        a.file {
     
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;
        }
        a.dir {
     
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;
        }
        a.up {
     
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;
        }
        html[dir=rtl] a {
     
            background-position-x: right;
        }
        #parentDirLinkBox {
     
            margin-bottom: 10px;
            padding-bottom: 10px;
        }
        #listingParsingErrorBox {
     
            border: 1px solid black;
            background: #fae691;
            padding: 10px;
            display: none;
        }
    </style>
    <title id="title">/home/liukairui/CODE/ 的索引</title>
</head>

<body>
    <div id="listingParsingErrorBox">糟糕!Google Chrome无法解读服务器所发送的数据。请<a
            href="http://code.google.com/p/chromium/issues/entry">报告错误</a>,并附上<a href="LOCATION">原始列表</a></div>
    <h1 id="header">/home/liukairui/CODE/ 的索引</h1>
    <div id="parentDirLinkBox" style="display: block;">
        <a id="parentDirLink" class="icon up" href="/home/liukairui/CODE/..">
            <span id="parentDirText">[上级目录]</span>
        </a>
    </div>
    <table>
        <thead>
            <tr class="header" id="theader">
                <th id="nameColumnHeader" tabindex="0" role="button">名称</th>
                <th id="sizeColumnHeader" class="detailsColumn" tabindex="0" role="button">
                    大小
                </th>
                <th id="dateColumnHeader" class="detailsColumn" tabindex="0" role="button">
                    修改日期
                </th>
            </tr>
        </thead>
        <tbody id="tbody">
            {
  {HERETOREPLACE}}
        </tbody>
    </table>
</body>
</html>
var fs=require("fs");
var http=require("http");

var server=http.createServer();
server.on("request",function(req,res){
   
    var content="";
    res.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readdir("./",function(error,files){
   
        if(error){
   
            res.end("404 Not Find");
            return;
        }else{
   
            files.forEach(function(FILENAME){
   
                content+=`<tr><td data-value="${
     FILENAME}/"><a class="icon dir" href="/home/liukairui/CODE/${
     FILENAME}/">${
     FILENAME}/</a></td><td class="detailsColumn" data-value="0"></td><td class="detailsColumn" data-value="1602264292">2020/10/10 上午1:24:52</td></tr>`
            })
        }
    });
    fs.readFile("./index.html",function(error,file){
   
        if(error)   
            res.end("404 Not Find");
        else{
   
            // 暴力使用字符串替换实现
            res.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liukairui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值