• 如何创建一个网站服务器


    1. 创建web服务器

    // 创建web服务器
    
    // 用于创建网站服务器的模块
    // 引用系统模块
    const http = require('http');
    
    // 创建web服务器
    // app对象就是网站服务器对象
    const app = http.createServer();
    
    // 当客户端发送请求的时候
    app.on('request', (req, res) => {
        // 响应
        res.end('<h1>hi ,user</h1>');
    });
    // 监听3000端口
    app.listen(3000); // 这里的端口号可以随便写,不一定是3000
    console.log('服务器已启动,监听3000端口,请访问localhost:3000');
    // 在powerShall中输入 nodemon app.js启动服务器,再在浏览器中输入localhost:3000
    

    2. HTTP协议

    2.1 http协议的概念

    超文本传输协议(http)规定了如何从网站服务器传输超文本到本地浏览器,它是基于客户端服务器架构工作,是客户端(用户)和服务器(网站)请求和应答的标准。

    2.2 报文

    在HTTP请求和响应的过程中传递的数据块就是报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式

    2.3 请求报文

    获取请求方式:req.method

    1. 请求方式(Request Method)
    • GET 请求数据
      在浏览器中输入网址使用的是get请求

    • POST 发送数据
      如何发送post请求:使用表单方式

    <body>
        <!-- 
            method: 指定当前表单提交的方式
            action:指定当前表单提交的地址
         -->
        <form method="post" action="http://localhost:3000">
            <input type="submit">
        </form>
    </body>
    

    1. 请求地址(Request URL)
        // 获取请求地址
        // req.url
    

    2.4 响应报文

    1. HTTP状态
    • 200 请求成功
    • 404 请求的资源没有被找到
    • 500 服务器端错误
    • 400 客户端请求有语法错误

    3. HTTP请求与响应处理

    3.1 请求参数

    客户端向服务器发送请求时,有时需要携带一些卡用户信息,客户信息需要通过请求参数的形式传递服务器端,比如登录操作。

    3.2 GET请求参数

    // 用于创建网站服务器的模块
    // 引用系统模块
    const http = require('http');
    // 用于处理url地址
    const url = require('url');
    
    // 创建web服务器
    // app对象就是网站服务器对象
    const app = http.createServer();
    
    // 当客户端发送请求的时候
    app.on('request', (req, res) => {
        console.log(req.url);
        // url.parse的参数:1)要解析的url地址 2)将查询参数解析成对象形式
        let { query, pathname } = url.parse(req.url, true);
        console.log(query.name);
        console.log(query.age);
    
        if (pathname == '/index' || pathname == '/') {
            return res.end('<h2>欢迎来到首页</h2>');
        } else if (pathname == '/list') {
            return res.end('welcome to listpage');
        } else {
            return res.end('no find');
        }
    });
    // 监听3000端口
    app.listen(3000);
    console.log('服务器已启动,监听3000端口,请访问localhost:3000');
    // 在powerShall中输入 nodemon app.js启动服务器,再在浏览器中输入localhost:3000
    

    3.3 POST请求参数

    • 参数被放置在请求体中进行传输
    • 获取POST参数需要使用data事件和end事件
    • 使用querystring系统模块将参数转换为对象格式
    // 导入系统模块querystring 用于将HTTP参数转换为对象格式
    const querystring = require('querystring');
    app.on('request', (req, res) => {
        let postData = '';
        // 监听参数传输事件
        // post参数是通过事件的方式接受的
        // data: 但请求参数传递的时候触发data事件
        // end:当参数传递完成的时候触发end事件
    
        req.on('data', (chunk) => postData += chunk;);
        // 监听参数传输完毕事件
        req.on('end', () => { 
            console.log(querystring.parse(postData)); 
        }); 
    });
    

    3.4 路由

    http://localhost:3000/index 首页
    http://localhost:3000/login 登录页面
    路由是指客户端请求地址与服务器端程序代码的对应关系。简单来说,就是请求什么响应什么

     // 1. 引入系统模块http
    // 2. 创建网站服务器
    // 3. 为网站服务器对象添加请求事件
    // 4. 实现路由功能
    // 1) 获取客户端的请求方式
    // 2) 获取客户端的请求地址
    const http = require('http');
    const url = require('url')
    const app = http.createServer();
    
    app.on('request', (req, res) => {
    
        // 获取请求方式
        const method = req.method.toLowerCase();
    
        // 获取请求地址
        const pathname = url.parse(req.url).pathname;
    
        res.writeHead(200, {
            'content-type': 'text/html;charset=utf8'
        })
    
        if (method == 'get') {
            if (pathname == '/' || pathname == '/index') {
                return res.end('欢迎来到首页')
            } else if (pathname == '/list') {
                return res.end('欢迎来到列表页');
            } else {
                return res.end('您访问的页面不存在');
            }
        } else if (method == 'post') {
            if (pathname == '/' || pathname == '/index') {
                return res.end('欢迎来到首页')
            } else if (pathname == '/list') {
                return res.end('欢迎来到列表页');
            } else {
                return res.end('您访问的页面不存在');
            }
        }
    });
    
    app.listen(3000);
    console.log('服务器启动成功');
    

    3.5 静态资源

    服务器端不需要处理,可以直接响应客户端的资源就是静太资源,例如CSS、JavaScript、image文件。

    3.6 动态资源

    相同的请求地址不同的响应资源,这种资源就是动态资源。
    例如:
    http:www.itcast.cn/article?id=1
    http:www.itcast.cn/article?id=2

    const http = require('http');
    const url = require('url');
    const path = require('path');
    const fs = require('fs');
    const mime = require('mime');
    const app = http.createServer();
    
    
    app.on('request', (req, res) => {
        // 获取用户的请求路劲
        let pathname = url.parse(req.url).pathname;
    
        pathname = pathname == '/' ? 'default.html' : pathname;
    
        // res.writeHead(200, {
        //     'content-type': 'text/html;charset=utf8'
        // })
    
        // 将用户的请求路劲转换为实际的服务器硬盘路劲
        let realPath = path.join(__dirname, 'public' + pathname);
    
        let type = mime.getType(realPath);
    
        // 读取文件
        // 如果文件读取成功 error为空,result 就是文件的内容
        // 如果文件读取失败 error里面存储的是失败信息, result为空
        fs.readFile(realPath, (error, result) => {
            // 文件读取失败
            if (error != null) {
                res.writeHead(404, {
                    'content-type': 'text/html;charset=utf8'
                })
                res.end('文件读取失败');
                return;
            }
            res.writeHead(200, {
                'content-type': type
            });
            res.end(result);
        })
    });
    
    app.listen(3000);
    console.log('服务器启动成功');
    

    4. Node.js异步编程

    4.1 同步API,异步API

    同步API:只有当前API执行完成后,才能继续执行下一个API

    异步API:当前API的执行不会阻塞后续代码的执行

    console.log('before');
    
    setTimeout(function() {
        console.log('last');
    }, 2000);
    
    console.log('after');
    
    // 输出结果为:before after last
    

    4.2 同步API,异步API的区别(获取返回值)

    同步API可以返回值中拿到API执行的结果,但是异步API是不可以的

    // 同步
    function sum(n1, n2) {
        return n1 + n2;
    };
    console.log(sum(2, 3));
    
    // 返回值为:5
    
    // 异步
    function getMsg() {
        setTimeout(function() {
            return {
                msg: 'hello node.js'
            }
        }, 2000);
        // 由于在执行getMsg时,遇到定时器所以直接跳到定时器的后面,添加return undefined执行,将其值返回给msg
        // return undefined
    }
    const msg = getMsg();
    
    console.log(msg);
    
    // 返回值为undefined
    

    4.3 回调函数

    自己定义函数让别人去调用

    // 异步
    function getMsg(callback) {
        setTimeout(function() {
            callback({
                msg: 'hello node.js'
            });
        }, 2000);
    
    }
    getMsg(function(date) {
        console.log(date);
    });
    
    

    4.4 同步API,异步API的区别(代码执行顺序)

    同步API从上到下依次执行,前面代码会阻塞后面代码的执行

    for (var i = 0; i < 10000; i++) {
        console.log(i);
    }
    console.log('执行后面的代码');
    

    异步API不会等待API执行完成后再向下执行代码

    console.log('代码开始执行');
    setTimeout(() => {
        console.log('2秒后执行的代码');
    }, 2000);
    setTimeout(() => {
        console.log('0秒后执行的代码');
    }, 0);
    console.log('代码结束执行');
    // 代码的执行结果
    // 代码开始执行
    // 代码结束执行
    // 0秒后执行的代码
    // 2秒后执行的代码
    

    4.5 代码执行顺序分析

    console.log('代码开始执行');
    setTimeout(() => {
        console.log('2秒后执行的代码');
    }, 2000); 
    setTimeout(() => {
        console.log('"0秒"后执行的代码');
    }, 0);
    console.log('代码结束执行');
    

    4.6 Node.js中的异步API

    const fs = require('fs');
    fs.readFile('1.txt', 'utf-8', (err, result1) => {
        console.log(result1);
        fs.readFile('2.txt', 'utf-8', (err, result2) => {
            console.log(result2);
            fs.readFile('3.txt', 'utf-8', (err, result3) => {
                console.log(result3);
            })
        })
    })
    

    如果异步API后面代码的执行依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题怎么解决呢?

    const fs = require('fs');
    
    let promise = new Promise((resolve, reject) => {
        fs.readFile('100.txt', 'utf8', (err, result) => {
            if (err != null) {
                return reject(err);
            } else {
                return resolve(result);
            }
        });
    });
    
    promise.then((result) => {
            console.log(result);
        })
        .catch((err) => {
            console.log(err);
        })
    

    4.7 Promise

    Promise出现的目的是解决Node.js异步编程中回调地狱的问题。

    4.8 异步函数

    异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。

    const fn = async () => {}
    
    async function fn() {}
    

    async关键字

    1. 普通函数定义前家async关键字 普通函数变成异步函数
    2. 异步函数默认返回promise对象
    3. 在一部函数内部使用return关键字进行结果返回,结果会包裹的promise对象中return关键字代替了resolve方法
    4. 在一部函数内部使用throw关键字抛出程序异常
    5. 调用异步函数再链式调用then方法获取函数执行结果
    6. 调用异步函数再链式调用catch方法获取异步函数执行的错误信息

    await

    1. await关键字只能出现在异步函数中
    2. await promise await后面只能写promise对象 写其他类型的API是不不可以的
    3. await关键字可是暂停异步函数向下执行 直到promise返回结果
    // 1. 在普通函数定义的前面加上async关键字 普通函数就变成了异步函数
    // 2. 异步函数默认的返回值使promise对象
    // 3. 在异步函数内保护使用throw关键字进行错误抛出
    
    
    
    // 4. await关键字
    // 它只能出现在异步函数中
    // awite后面跟promise对象 它可以暂停异步函数的执行,等待promise对象返回后再向下执行函数
    
    // async function fn() {
    //     throw '发生了一些错误';
    //     return 123;
    // }
    // // console.log(fn());
    // fn().then(function(data) {
    //         console.log(data);
    //     })
    //     .catch(function(err) {
    //         console.log(err);
    //     })
    
    async function p1() {
        return 'p1';
    }
    async function p2() {
        return 'p2';
    }
    async function p3() {
        return 'p3';
    }
    async function run() {
        let r1 = await p1();
        let r2 = await p2();
        let r3 = await p3();
        console.log(r1);
        console.log(r2);
        console.log(r3);
    }
    run();
    
    const fs = require('fs');
    
    const promisify = require('util').promisify;
    const readFile = promisify(fs.readFile);
    async function run() {
        let r1 = await readFile('1.txt', 'utf8');
        let r2 = await readFile('2.txt', 'utf8');
        let r3 = await readFile('3.txt', 'utf8');
        console.log(r1);
        console.log(r2);
        console.log(r3);
    }
    run();
    

    4.9 Node.js全局对象global

    在浏览器中全局对象是window, 在Node中全局对象是global。

    Node中全局对象有以下方法, 在任何地方使用, global可以省略。

      1. console.log(); 在控制台中输出
      1. setTimeout() 设置超时定时器
      1. clearTimeout() 清除超时时定时器
      1. setInterval() 设置间歇定时器
      1. clearInterval() 清除间歇定时器
  • 相关阅读:
    Data Structure Graph: cycle in a directed graph
    Data Structure Trie: suffix problem
    Data Structure Stack: Reverse a stack using recursion
    Data Structure Stack: Infix to Postfix
    Data Structure Linked List: Flattening a Linked List
    单纯形方法(Simplex Method)
    阿里云服务器9.9元/月,学生专享!
    佣金百万so easy!阿里云推广联盟喊你来赚钱
    阿里云双11绽放在即,1111元代金券天天送!
    阿里云新人礼,马上领取!
  • 原文地址:https://www.cnblogs.com/counter/p/14669483.html
Copyright © 2020-2023  润新知