@
一、系统模块http -- 创建web服务端
http 模块 是 Node.js 官方提供的、用来 创建 web 服务器 的模块。
不需要使用 IIS、Apache 等这些第三方 web 服务器软件,可直接通过 http 模块提供的 http.createServer()
方法,就能方便的把一台普通的电脑,变成一台最基本的 Web 服务器,从而对外提供 Web 资源服务。
//app.js
// 1. 引用http系统模块
const http = require('http');
// 2. http.createSercer(): 创建web服务器
const server = http.createServer();
// 3. 为服务器实例绑定 request 事件
server.on('request', (req, res) => {
console.log('someone visit my web server')
})
// 4. 启动服务器
// Server.listen(端口号, callback):监听端口,网站服务器必须监听端口,否者无法向外服务
server.listen(3000, () => {
console.log('服务器已启动,监听3000端口,请访问 localhost:3000')
});
之后通过命令行的方式开启服务器端node app.js
二、NodeJS服务端接收并处理客户端请求
server.on('requeset', function(req, res){})
在服务器创建成功后,调用通过 on()
为服务器注册的 request
事件 并绑定处理函数,函数中可传入两个参数
其中参数 req
表示 客户端请求相关的数据或属性
另一个参数 res
表示 服务器响应相关的数据或属性
举例:
// 通过 on 方式 添加 请求事件 request, 后面函数为事件绑定函数, 当客户端发送请求到服务端就执行该函数;
/*
req : 代表请求对象,该对象保存了请求相关的信息
res : 代表响应对象, 对客户端的请求进行响应
*/
server.on('request', (req, res) => {
//req.method : 获取请求方式
console.log(req.method);
//req.url : 获取请求地址
console.log(req.url);
//req.headers : 获取请求报文
console.log(req.headers);
/*
res.writedHead(parms1, parms2): 设置响应报文
parms1: 设置响应头中的 http状态码, Number
parms2: 设置响应头中的头部字段, object
注意:res.writedHead() 需要在 res.end() 之前调用才有效
*/
res.writeHead(200, {
//指定响应头中Content-Type字段值,值为响应内容类型,指定字符编码以免乱码
'Content-Type': 'text/html;charset=utf8'
});
//res.end() : 根据请求响应客户端
res.end('这是服务端响应给客户端页面的内容');
});
③ 解决中文乱码问题
当调用 res.end()
方法,向客户端发送中文内容的时候,会出现乱码问题,此时,需要手动设置内容的编码格式:
server.on('request', (req, res) => {
// 响应内容包含中文
const str = `您的请求的 url 地址是 ${req.url}, 请求的 method 类型是 ${req.method}`;
// 为了防止显示中文乱码问题,需要设置响应头 Content-Type 的值为 text/html; charset=utf-8
res.setHeader('Content-Type', 'text/html; charset=utf-8')
// 把包含中文的内容,响应给客户端
res.end(str)
})
三、NodeJS 服务端处理请求参数
1. 系统模块url -- 处理GET请求参数
get请求参数一般放置在浏览器地址栏中,例如:http://localhost:3000/?name=zhangsan&age=20
- 参数获取需要借助系统模块url,url模块用来处理url地址
- 通过 url.parse() 来解析
req.url
地址,并更具第二参数判断是否以对象的方式饭返回
//eg :在服务端接收到客户端请求中的参数
const http = require('http');
// 导入url系统模块 用于处理url地址
const url = require('url');
const app = http.createServer();
app.on('request', (req, res) => {
console.log(req.url);
console.log(url.parse(req.url, true));
// 将url路径的各个部分解析出来并返回对象
// true 代表将参数解析为对象格式
let {query, pathname} = url.parse(req.url, true);
console.log(query);
console.log(pathname)
});
app.listen(1234);
2. 系统模块querystring -- 处理POST请求参数
-
参数被放置在请求头中发送到服务端
-
使用 querystring系统模块 将post参数转换为 对象格式
-
获取POST参数需要使用
data
事件和end
事件
如果post参数数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data
事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接;
当请求体数据接收完毕之后,会自动触发 req 的 end
事件。
// 导入系统模块querystring 用于将HTTP参数转换为对象格式
const querystring = require('querystring');
app.on('request', (req, res) => {
//拼接post请求参数
let postData = '';
// post参数是通过事件的方式接受的
// 监听参数传输事件, 当请求参数传递的时候出发data事件, params: post请求传输的数据
req.on('data', (params) => {
console.log(params)
postData += params
});
// 监听参数传输完毕事件, 当参数传递完成的时候出发end事件
req.on('end', () => {
// 通过querystring模块的parse方法解析 字符串参数postData 成对象格式并返回
console.log(postData )
console.log(querystring.parse(postData))
});
});
四、NodeJS服务端实现路由
1. 原生实现路由
路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说,就是请求什么响应什么,动态响应内容:
路由实现代码
// 当客户端发来请求的时候
app.on('request', (req, res) => {
// 获取客户端的请求路径
let { pathname } = url.parse(req.url);
res.setHeader('Content-Type', 'text/html; charset=utf-8')
if (pathname == '/' || pathname == '/index') {
res.end('欢迎来到首页');
} else if (pathname == '/list') {
res.end('欢迎来到列表页页');
} else {
res.end('抱歉, 您访问的页面出游了');
}
});
简单案例:
const http = require('http');
const url = require('url');
const app = http.createServer();
const querystring = require("querystring");
app.on('request', (req, res) => {
let method = req.method.toLowerCase();
let path = url.parse(req.url);
let postparms = '';
res.writeHead(200, {
'Content-Type': 'text/html;charset=utf8'
})
if (method == "get") {
switch (path.pathname) {
case '/':
case '/index':
res.end('<h2>欢迎来到首页<h2>');
break;
case '/list':
res.end('<h2>欢迎来到列表页<h2>');
break;
case '/login':
res.end(`<h2>欢迎来到登录界面</h2>
<form method="POST" action="http://localhost:1234/success">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
</form>
`);
break;
default:
res.end('<h2 style="color: red">您访问的页面不存在!<h2>');
}
} else if (method == "post") {
req.on('data', (parms) => {
postparms += parms;
})
req.on('end', () => {
postparms = querystring.parse(postparms);
let username = postparms.username;
let password = postparms.password;
switch (path.pathname) {
case '/success':
res.end("登录成功!<br>您的用户名为:" + username + "<br>您的密码为" + password);
}
})
}
})
app.listen(1234);
console.log('服务器已启动,监听1234端口,请访问 localhost:1234');
2. 第三方模块 router
功能:实现路由
使用步骤:
- 获取路由对象
- 调用路由对象提供的方法创建路由
- 启用路由,使路由生效
//引入router第三方模块并返回一个函数
const getRouter = require('router')
//通过调用getRouter()获取路由对象router, 实际也是函数
const router = getRouter();
/*路由对象.get(参数1, 参数2)
功能:用来接收get请求
参数1:Url请求地址
参数2:当前请求处理函数,
req: 请求对象
res: 响应对象
*/
router.get('/add', (req, res) => {
res.end('Hello World!')
})
/*路由对象.post()
功能:用来接收post请求
参数:与get()一样
*/
router.post('/',(req, res) => {
res.end();
})
/*
server: 由http模块创建的服务器对象
通过给服务器对象添加请求事件捕获请求并开启路由功能
*/
server.on('request', (req, res) => {
/*
通过调用router()启用路由功能,
router函数根据请求类型和请求地址自动匹配get()或post()
参数说明:
req:请求对象
res:响应对象
callback:当请求结束后会自动调用这个回调函数,它是必填参数
*/
router(req, res, () => {})
})
五、NodeJS服务端响应静态资源
服务器端不需要处理,可以直接响应给客户端的资源就是静态资源,例如CSS、JavaScript、image文件。
① 第三方模块 mime
app.on('request', (req, res) => {
// 获取用户的请求路径
let pathname = url.parse(req.url).pathname;
pathname = pathname == '/' ? '/default.html' : pathname;
// 将用户的请求路径转换为实际的服务器硬盘路径, join方法可自动生成路径链接符
let realPath = path.join(__dirname, 'public' + pathname);
//识别当前请求文件的文件类型
let type = mime.getType(realPath)
// 读取文件
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,便于浏览器正确读取文件格式
'content-type': type
})
res.end(result);
});
});
② 第三方模块 serve-static
serve-static - npm (npmjs.com)
功能:实现静态资源访问服务
步骤:
- 引入serve-static模块获取创建静态资源服务功能的方法
- 调用方法创建静态资源服务并指定静态资源服务目录
- 启用静态资源服务功能
//导入第三方模块'serve-static' , 并返回了一个方法
const serveStatic = require('serve-static')
/*调用返回的方法: serveStatic(参数1)
功能:实现静态资源访问服务功能
参数1:静态资源文件目录(绝对路径)
返回值:一个方法
*/
const serve = serveStatic('public')
//server: 由http模块创建的服务器对象
server.on('request', () => {
/*
启用静态资源服务
方法实现过程:根据请求对象来判断当前请求是否访问静态资源,如果是静态资源,它会把静态资源直接响应给客户端
callback: 请求结束后会自动调用回调函数,必填参数
*/
serve(req, res, callback);
})
server.listen(3000)