服务器基础概念
学习NodeJS的意义
- 了解客户端浏览器与服务端后台的交互过程,可以在以后的前端开发工作中与后台人员之间的沟通更加容易理解
- 虽然以后工作中不一定用的上nodejs,但是通过对服务端开发的了解,能够让你在日常工作中与公司后台人员之间的沟通变得更加轻松
- 了解服务端开发的一些特性,可以在以后的工作中,当我们前端与后台交互出现bug问题时,能够更快速的定位bug是出现在自己的客户端还是别人的服务端。
- 作为一名前端人员,如果对后台不了解,那么以后在与后台交互的开发中有可能明明是后台的问题,但是由于自身对后台的不了解再加上前期的经验不足,导致解决问题的时间增加。
- 了解服务端开发的过程,可以为以后的职业发展打下一定的基础(全栈工程师)
什么是Nodejs
- Node 是一个构建于 Chrome V8引擎之上的一个Javascript 运行环境
- Node是一个运行环境,作用是让js拥有开发服务端的功能
- Node使用事件驱动、非阻塞IO模型(异步读写)使得它非常的轻量级和高效
- Node中绝大多数API都是异步(类似于ajax),目的是提高性能
- Node中的NPM是世界上最大的开源库生态系统(类似于github)
服务端js与客户端js区别
- 客户端JavaScript由三部分组成
- ECMAScript:确定js的语法规范
- DOM:js操作网页内容
- BOM:js操作浏览器窗口
- node中的JavaScript
- 组成
- ECMAScript
- 核心模块
- 第三方模块
- 基本的语法和写法和之前的js没有本质的区别
- 在nodejs中使用dom与bom的api程序会报错
- 服务器端没有界面
- 压根不需要操作浏览器和页面元素
在学习创建服务器前需要了解基本的核心模块:
nodejs核心模块
- readFile读取文件 :
1.导入文件模块
const fs = require('fs');
2.异步读取文件
-
第一个参数:文件路径
-
第二个参数:编码格式 (可选参数,默认为buffer二进制)
-
第三个参数:读取回调操作(异步操作)
-
err:如果读取成功,err为null, 否则读取失败(一般文件路径错误或者找不到文件)
-
data:读取到的数据
fs.readFile('./data/aaa.txt','utf-8',(err,data)=>{ if(err){ console.log(err); //抛出异常,throw的作用就是让node程序终止运行,方便调试 throw err; }else{ console.log(data); }; });```
fs 模块是node提供的核心模块--装好了node就能直接使用这个核心模块
fs核心模块可以进行文件(目录)的相关操作
require方法可以引入模块,并返回一个对象,通过返回的对象可以调用模块中提供的api
语法: const myfs = require('fs')
- writeFile写入文件 :
1.导入文件模块
const fs = require('fs');
2.异步写文件
-
第一个参数:文件路径
-
第二个参数:要写入的数据
-
第三个参数:文件编码 默认utf-8
-
第四个参数: 异步回调函数
-
err: 如果成功,err为null.否则读取失败
fs.writeFile('./data/bbb.txt','黑马程序员','utf-8',(err)=>{ if(err){ throw err; }else{ console.log('写入成功'); }; });```
-
appendFile追加内容 :
1.可以往指定的文件中追加内容--不会覆盖原文件的内容 -
path路径模块 :
1.在服务端开发中,一般不要使用相对路径,而使用绝对路径
2.在nodejs中,每一个js文件都有两个全局属性,它可以帮助我们获取到文件的绝对路径 -
__filename:当前js文件 所在目录 的绝对路径,当前文件的全路径:目录+文件名称
-
__dirmame:当前js文件的绝对路径,当前文件所在的目录
示例:
1.导入文件模块
const fs = require('fs');
2.如果想要获取当前文件夹下其他文件绝对路径,可以使用 __dirname属性来拼接
let path = __dirname + '/文件名';
(注意:通过path.join可以生成规范化的路径:path.join(__dirname, '/views/login.html') 会自动拼接成规范地址)
什么是服务器
一个管理资源并为用户提供服务的计算机,通常分为文件服务器(能使用户在其它计算机访问文件,我们平时访问的网页也一个一个的文件),数据库服务器和应用程序服务器;能够提供以上服务的计算机,我们也称其为网络主机(Host)
基本访问流程
- 输入主机地址
- 指定端口(如果没有指定,则默认为80)
- 指定需要访问的资源路径(要参照服务器的设定)
- 发起请求
- 获取服务器返回的结果并处理
如何创建服务器:
```
1. 服务器一定要遵守http协议,所以首先要引入http协议
const http = require('http')
2.根据http协议创建一个服务器
const server = http.createServer()
3.添加指定端口的监听(127.0.0.1:本机圆环地址,如果以本机做为服务器,默认的地址就是127.0.0.1)
server.listen(3003, () => {console.log('http://127.0.0.1:3003')})
4. 监听用户的请求
// 当用户向这个服务器发起指定端口的请求时,就会自动的触发request事件
// 在事件处理函数中,有两个参数:
req:就是客户端传递给服务器的请求数据(请求报文)-- request,
res:就是服务器响应给客户端的数据 --response
// 如果监听到用户的请求,通过设置的资源url用于响应用户特定的请求---路由
server.on('request', (req, res) => {
// 服务器响应回客户端的内容永远都是字符串
// 但是你需要注意的是,字符串是带格式的
res.end('为什么写个中文我看不懂aabbcc')
});
```
服务器如何响应用户不同的请求
响应客户端请求
// 1.引入http模块
const http = require('http')
// 2.创建服务器
// createServer方法可以创建一个node服务器
const server = http.createServer()
// 3.添加服务器的端口监听
// 第一个参数:监听的端口,以后只有这个端口的请求,当前服务器才会响应
// 第二个参数:回调函数,当服务器启动的时候会调用这个回调函数
server.listen(3000,function(){
console.log('服务器开好了: http://127.0.0.1:3000')
})
// 4.添加用户请求的监听,只要用户发起了针对当前服务器3000端口的请求,就会调用回调函数进行处理
// 这个回调函数的参数和之前createServer中回调函数的参数一样
server.on('request',function(req,res){
res.end('hello world')
})
响应客户端页面
// 1.引入http模块
const http = require('http')
// 读取文件需要fs模块
const fs = require('fs')
// 2.创建服务器
const server = http.createServer()
// 3.添加服务器的端口监听
server.listen(3000,function(){
console.log('服务器开好了: http://127.0.0.1:3000')
})
// 4.添加用户请求的监听,只要用户发起了针对当前服务器3000端口的请求,就会调用回调函数进行处理
// 这个回调函数的参数和之前createServer中回调函数的参数一样
server.on('request',function(req,res){
// 读取首页并返回,这里就需要使用到fs核心模块了
// 细节:这里不需要设置编码,因为html页面已经有默认的编码了
fs.readFile(__dirname+"/views/index.html",function(err,data){
if(err){
res.end('404')
}else{
res.end(data)
}
})
})
监听客户端请求并响应不同页面
// 1.引入http模块
const http = require('http')
// 读取文件需要fs模块
const fs = require('fs')
// 2.创建服务器
const server = http.createServer()
// 3.添加服务器的端口监听
server.listen(3000, function () {
console.log('服务器开好了: http://127.0.0.1:3000')
})
// 4.添加用户请求的监听,只要用户发起了针对当前服务器3000端口的请求,就会调用回调函数进行处理
// 这个回调函数的参数和之前createServer中回调函数的参数一样
server.on('request', function (req, res) {
// 想要根据用户请求返回不同的页面,关键是需要知道用户到底发了什么请求
// req.url:可以获取当前用户请求的url,如果客户端没有指定url,那么它默认为/
let url = req.url
// 这里需要注意的是,在node服务器中使用console,会在服务器端中进行打印,而不是在浏览器端打印输出呢
console.log(url)
// 我们可以看到,用户的不同请求,url是不一样的,所以我们需要判断当前的url以决定返回什么样的页面
// 对于url的判断,我们在开发的时候一般是在后台进行约定,前端需要遵守
// 这里我们约定 /或/index 就是要请求首页, /login 就是要请求登陆页
if (url == '/' || url == '/index') {
fs.readFile(__dirname + "/views/index.html", function (err, data) {
if (err) {
res.end('404')
} else {
res.end(data)
}
})
}else if(url == '/login'){
fs.readFile(__dirname + "/views/login.html", function (err, data) {
if (err) {
res.end('404')
} else {
res.end(data)
}
})
}else{
res.end('404')
}
})
响应数据回客户端
// 1.引入http模块
const http = require('http')
// 读取文件需要fs模块
const fs = require('fs')
// 2.创建服务器
const server = http.createServer()
// 3.添加服务器的端口监听
server.listen(3000, function () {
console.log('服务器开好了: http://127.0.0.1:3000')
})
// 4.添加用户请求的监听,只要用户发起了针对当前服务器3000端口的请求,就会调用回调函数进行处理
// 这个回调函数的参数和之前createServer中回调函数的参数一样
server.on('request', function (req, res) {
// 想要根据用户请求返回不同的页面,关键是需要知道用户到底发了什么请求
// req.url:可以获取当前用户请求的url,如果客户端没有指定url,那么它默认为/
let url = req.url
// 这里需要注意的是,在node服务器中使用console,会在服务器端中进行打印,而不是在浏览器端打印输出呢
console.log(url)
// 我们可以看到,用户的不同请求,url是不一样的,所以我们需要判断当前的url以决定返回什么样的页面
// 对于url的判断,我们在开发的时候一般是在后台进行约定,前端需要遵守
if (url == '/getUserList') {
fs.readFile(__dirname + "/data/users.json",'utf-8', function (err, data) {
if (err) {
res.end('404')
} else {
res.end(data)
}
})
}else{
res.end('404')
}
})
响应客户端不同类型的请求
1.通过req.method可以获取当前客户端的请求方式
2.根据req.method的值的不同,进行相应的处理操作
响应get方式的请求
// 1.引入协议
var http = require('http')
var fs = require('fs')
// 2.创建服务器
var server = http.createServer()
// 3.添加对端口的监听
server.listen(3000,function(){
console.log('http://127.0.0.1:3000')
})
// 4.添加用户请求的监听
server.on('request', function (req, res) {
// 设置允许跨域请求
res.setHeader('Access-Control-Allow-Origin', '*');
// req.url:可以获取当前客户端请求的url,如果客户端没有指定url,那么它默认为 /
let url = req.url
// req.method:可以获取当前客户端请求方式
let method = req.method
console.log(method) // GET POST
// 如果是以get方式请求/getUserList,才能匹配从而响应
if (method == 'GET' && url == '/getUserList') {
fs.readFile(__dirname + "/data/users.json",'utf-8', function (err, data) {
if (err) {
res.end('err')
} else {
res.end(data)
}
})
}
else{
res.end('404')
}
})
页面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<a href="http://127.0.0.1:3000/getUserList">单击我可以获取到用户列表数据</a>
</body>
</html>
响应post方式的请求
// 1.引入http模块
const http = require('http')
// 解析参数的querystring模块
const querystring = require('querystring')
// 2.创建服务器
const server = http.createServer()
// 3.添加服务器的端口监听
server.listen(3000, function () {
console.log('服务器开好了: http://127.0.0.1:3000')
})
// 4.添加用户请求的监听
server.on('request', function (req, res) {
// 设置允许跨域请求
res.setHeader('Access-Control-Allow-Origin', '*');
// req.url:可以获取当前客户端请求的url,如果客户端没有指定url,那么它默认为/
let url = req.url
// req.method:可以获取当前客户端请求方式
let method = req.method
// 如果是以POST方式请求/login,才能匹配从而响应
if (method == 'POST' && url == '/login') {
// 接收参数
var postData = '';
//给req注册一个data事件,这个事件可以实现post方式请求的参数的接收。post允许客户端发送大容量的参数,如果参数较多,它支持分批进行参数的接收,当客户端每发送一次数据流,都会触发里面的回调函数,我们需要主动将这些数据拼接起来
req.on('data', function(chuck){
//具体多少次,取决于客户端带宽
postData += chuck;
});
//2.给req注册一个end事件。当客户端post数据全部发送完毕之后,就会触发这个事件
req.on('end', () => {
//3.使用querystring模块解析接收完成的post参数数据
let postObj = querystring.parse(postData);
// 登陆验证
if(postObj.username == 'admin' && postObj.password == '123456'){
res.end('yes')
}else{
res.end('no')
}
})
}
else {
res.end('404')
}
})
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>
</head>
<body>
<form method="post" action='http://127.0.0.1:3000/login'>
用户名:<input type="text" name='username' placeholder="请输入用户名"><br>
密码: <input type="password" name='passwrod' placeholder="请输入密码"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>