服务器端基本概念学习记录


服务端基础概念

网站组成

网站应用程序主要分为两大部分:客户端和服务器端

URL

URL统一资源定位符,又叫URL,专为标识Internet网上资源位置而设的一种编址方式,就是我们平时所说的网页地址;
URL 的组成:
传输协议://服务器IP或域名:端口/资源所在位置标识
http://www.itcast.cn/news/20181018/09152238514.html
http:超文本传输协议,提供了一种发布和接收HTML页面的方法;

开发过程中客户端和服务器端说明

开发阶段客户端和服务器端使用同一台电脑,自己电脑地址 localhost

创建web服务器

在这里插入图片描述
创建web服务器代码示例, 在power Shell窗口中执行nodemon app.js,再在浏览器中输入localhost:3000就可以看到res.end()里面的内容:

//用于创建网站服务器的模块
const http = require('http');
//app对象就是网站服务器对象
const app = http.createServer();
//当客户端有请求来的时候 监听客户端请求
app.on('request', (req, res) => {
    res.end('<h2>hello user</h2>');
});
//监听3000端口 其他号也可以只要没被占用
app.listen(3000);
console.log('网站服务器启动成功');

HTTP协议

HTTP 协议就是客户端和服务器端沟通的规范;规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器架构工作。
在这里插入图片描述
报文
在HTTP请求和响应过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式
在这里插入图片描述

  1. 请求方式req.method
    GET 请求数据
    POST 发送数据 可以通过表单的方式指定请求方式是post或者get
    地址相同的时候根据这个请求方式不同可以响应不同 的内容
    代码示例如下
app.on('request', (req, res) => {
    //获取请求方式 req.method
    console.log(req.method);
    if (req.method == 'POST') {
        res.end('post')
    } else if (req.method == 'GET') {
        res.end('get');
    }
    // res.end('<h2>hello user</h2>');
});

npm参考文档
nodejs官网

  1. 获取请求地址req.url
    req.url代码示例
if (req.url == '/index' || req.url == '/') {
        res.end('welcome to homepage');
    } else if (req.url == '/list') {
        res.end('welcome to listpage');
    } else {
        res.end('sorry not found');
    }
  1. 获取请求报文信息req.headers
    console.log(req.headers['accept']);
  1. 响应报文
    HTTP状态码:
    200请求成功
    404请求资源没有被找到
    500服务器端错误
    400客户端请求有语法错误
    内容类型:
    text/html
    text/css
    application/javascript
    image/jpeg
    application/json
    以上内容通过以下代码设置:可以解析html文件,注意要设置文本编码方式charset 否则中文会报错
res.writeHead(200, {
        'content-type': 'text/html;charset=utf8',
    });

HTTP请求与响应处理

  1. 请求参数
    客户端向服务器端发送请求时,有时需要携带一些客户信息,客户信息需要通过请求参数的形式传递到服务器端,比如登录操作;
    get请求参数
    参数被放置在浏览器地址栏中:例如:http://localhost:3000/?name=zhangsan&age=20
    需要通过req.url得到这个输入的地址,然后使用url.parse(第一个参数,第二个参数)解析
    代码如下:
//1.第一个参数是要解析的url
    //2.第二个参数是将查询参数解析成对象形式
    console.log(url.parse(req.url, true));

解析结果
在这里插入图片描述
在解析的时候出现了问题,上面代码有null prototype,解决方法
nodejs中文网
为了解决上面废弃的url.parse方法使用新的

    const params = new URL(req.url, 'http://localhost:3000/');
    // console.log(params);
    console.log(params.searchParams.get('name'));//打印zhangsna
    console.log(params.searchParams.get('age'));//打印20

904
利用解构上面代码又可以更改为:

//利用解构写出下面的代码
    const { searchParams, pathname } = new URL(req.url, 'http://localhost:3000/');
    // console.log(params);
    console.log(searchParams.get('name'));
    console.log(searchParams.get('age'));
    if (pathname == '/index' || req.url == '/') {
        res.end('<h2>欢迎来到首页</h2>');
    } else if (pathname == '/list') {
        res.end('welcome to listpage');
    } else {
        res.end('sorry not found');
    }

POST请求参数
数据放在了form data里面
在这里插入图片描述

  • post参数通过事件的方式接收 不是一次接收完的
  • data 当请求参数传递的时候触发事件
  • end 当参数传递完成的时候触发end事件
    post获取参数
    querystring.parse()遇到的问题
 console.log(querystring.parse(postParams));

输出的是:
在这里插入图片描述
改正以后:参考博客

let params1 = JSON.stringify(querystring.parse(postParams));
            let obj = JSON.parse(params1);
            console.log(obj);

在这里插入图片描述
post请求参数被放置在请求体(报文)中进行传输,而get请求参数把参数放在了地址url中进行获取
获取POST参数需要使用data和end事件
使用querystring系统模块将参数转换为对象格式,但是官方文档,
在这里插入图片描述
所以需要使用JSON
路由
http://localhost:3000/index
http://localhost:3000/login
路由概念:客户端请求地址与服务器端程序代码对应关系,即请求什么就响应什么。
在这里插入图片描述
路由代码示例,post请求方式没有写

// 1. 引入系统模块http
// 2.创建网站服务器
// 3.为网站服务器对象添加请求事件
// 4.实现路由功能
//获取客户端请求方式
//获取客户端请求地址
const http = require('http');
const url = require('url');

const app = http.createServer();

app.on('request', (req, res) => {
    //获取请求方式 toLowerCase()转换为小写
    const method = req.method.toLowerCase();
    //获取请求地址
    const { searchParams, pathname } = new URL(req.url, 'http://localhost:3000/');
    //响应报文编码方式
    res.writeHead(200, {
        'content-type': 'text/html;charset=utf8'
    });

    if (method == 'get') {
        if (pathname == '/' || pathname == '/index') {
            res.end('欢迎来到首页index');
        } else if (pathname == '/list') {
            res.end('欢迎来到列表页list');
        } else {
            res.end('您访问的页面不存在哦!请返回');
        }
    } else if (method == 'post') {

    }
});

app.listen(3000);
console.log('网站服务器启动成功');
//获取请求地址
    const { searchParams, pathname } = new URL(req.url, 'http://localhost:3000/');

静态资源
服务器端不需要处理,可以直接响应给客户端的资源叫静态资源;例如CSS、JavaScript、image文件。
http://www.itcast.cn/images/logo.png
静态资源访问:
获取用户请求路径 __dirname获取绝对路径
将用户请求路径转换为实际的服务器硬盘路径let realPath = path.join(__dirname, 'public' + pathname);

//获取用户请求路径
    // const { searchParams, pathname } = new URL(req.url, 'http://localhost:3000/');
    let pathname = new URL(req.url, 'http://localhost:3000/').pathname;
    res.end(path.join(__dirname, 'public' + pathname));

系统读取实际路径成功后会调用箭头函数,如果文件读取成功error就是空result是文件内容;失败的话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);
    });

使用第三方模块mime获取当前文件类型html css等类型,然后返回

let type = mime.getType(realPath);
res.writeHead(200, {
            'content-type': type
        });

动态资源
相同的请求地址不同的响应资源,叫动态资源
http://www.itcast.cn/article?id=1
http://www.itcast.cn/article?id=2

Node.js异步编程

同步API 异步API

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

console.log('before');
console.log('after');

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

console.log('before');
setTimeout(() => {
    console.log('last');
}, 2000);
console.log('after');

定时器就是异步API
同步API,异步API区别:
异步API无法通过返回值方式拿到API 执行结果,是通过回调函数拿到异步API执行结果的;

function getMsg() {
    setTimeout(function() {
        return { msg: 'hello node.js' }
    }, 2000);
}
const msg = getMsg();
console.log(msg); //打印undedined

以下代码通过回调函数拿到异步API执行结果示例1

function getData(callback) {
    callback('1234');
};
getData(function(n) {
    console.log('callback函数被调用了');
    console.log(n);
});
//程序执行结果打印:
// callback函数被调用了
// 1234

以下代码通过回调函数拿到异步API执行结果示例2

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

代码执行顺序不一样
同步API从上到下依次执行,前面代码会阻塞后面代码
同步API执行

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

上面代码执行结果
在这里插入图片描述
异步API不会等待API执行完成后再执行后面的代码
异步API执行

console.log('代码开始执行');
setTimeout(function() {
    console.log('2s');
}, 2000);
setTimeout(function() {
    console.log('0s');
}, 0);
console.log('代码结束执行');

上面代码执行结果
在这里插入图片描述
在这里插入图片描述
异步API中的一些问题:
异步API:

fs.readFile('./demo.txt',(err,result)=>{});
var server=http.createServer();
server.on('request',(req,res)=>{});

问题来了,如果异步API后面代码的执行依赖当前的API执行结果该怎么办呢???

fs.readFile('./demo.txt',(err,result)=>{});
consloe.log('文件读取结果');

现在就有一个需求:依次读取文件A、文件B、文件C。
第一种解决方法示例,但是不采用这种方法不方便代码维护

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

以上代码运行结果如下
在这里插入图片描述
使用Promise解决Node.js异步编程中回调地狱(也叫回调陷阱)的问题;promise参考文献 1 2
第2种解决方法示例Promise
1.首先是使用Promise 然后用函数把Promise实例化的对象包装成一个函数

function P1() {
    return new Promise((resolve, reject) => {
        fs.readFile('./1.txt', 'utf8', (err, result1) => {
            resolve(result1);
        });
    });
}

2.使用return P2()使得后面可以继续使用then(), 利用链式编程

P1().then((r1) => {
        console.log(r1);
        return P2();
    })

promise方法完整代码示例

const fs = require('fs');
//3个异步API 所以需要三个promise
function P1() {
    return new Promise((resolve, reject) => {
        fs.readFile('./1.txt', 'utf8', (err, result1) => {
            resolve(result1);
        });
    });
}

function P2() {
    return new Promise((resolve, reject) => {
        fs.readFile('./2.txt', 'utf8', (err, result2) => {
            resolve(result2);
        });
    });
}

function P3() {
    return new Promise((resolve, reject) => {
        fs.readFile('./3.txt', 'utf8', (err, result3) => {
            resolve(result3);
        });
    });
}
P1().then((r1) => {
        console.log(r1);
        return P2();
    })
    .then((r2) => {
        console.log(r2);
        return P3();
    })
    .then((r3) => {
        console.log(r3);

    })

异步函数
异步函数是异步编程语法的终极解决方案,可以将异步代码写成同步形式,让代码不再又回调函数嵌套,使代码更加清晰;
async关键字

  • 普通函数定义前加async关键字 普通函数便异步函数
  • 异步函数默认返回promise对象
  • 在异步函数内部使用return关键字进行结果返回,结果会被包裹的promise对象中 return关键字代替了resolve方法
  • 在异步函数内部使用throw关键字进行错误抛出 执行完throw便不再执行后面代码
  • await关键字 只能出现在异步函数中 await promise可以暂停异步函数执行 等待promise对象返回结果再向下执行

代码示例

const fn=async()=>{};
async function fn(){};
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();

await关键字

  • await只出现在异步函数中
  • await promise await 后面只能写promise对象 写其他类型的API是不可以的
  • await关键字使得暂停异步函数向下执行直到返回promise返回结果;

使用异步函数实现依次读取 a b c三个文件

const fs = require('fs');
//让现有的异步函数API让其返回promise对象,从而支持执行异步函数语法;
const promisify = require('util').promisify;
//readFile为promisify对象 所以可以使用await关键字
const readFile = promisify(fs.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();

Node.js全局对象global

在这里插入图片描述

global.console.log('我是');
global.setTimeout(function() {
    console.log('123');
}, 2000)

总结

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值