web服务器
1.服务器的相关概念
1.1服务器与客户端
服务器的概念:提供网络服务的一台机器,通过在自己的电脑上安装特殊的软件(或者是运行某段特殊的代码)来提供服务
-
服务器 = 电脑 + 可以给其他电脑提供服务的软件
-
服务器:提供服务的是服务器
-
客户端 = 电脑 + 软件(平时个人使用的软件)
-
客户端:享受服务的是客户端
1.2服务器的类型
根据服务不同,服务器的类型也不同:
- web服务器:安装apache, tomcat, iis, 或者在 node.js 环境写代码 来提供:图片浏览,新闻浏览…等服务的服务器。
- ftp服务器:安装serv-U软件,为其它电脑提供文件下载,共享服务。
- 数据库服务器:安装mysql软件,为其它电脑提供数据库服务。
- …
1.3web服务器
- 用户通过浏览器来享受web服务器提供的服务
- 我们用url地址来访问某个web服务器上的资源
- 浏览器端发起请求,web服务器收到请求后,响应这请求,并将处理结果返回给浏览器
- 浏览器端与web服务器是通过http(或者是https)协议来进行请求和响应的
1.4IP地址
全称:I ntternet P rotocol Address
作用:标识一个网络设备在某个具体的网络当中的地址。我们要想访问某个电脑上的资源,首先要找到它对应的IP
分类:IPV4 IPV6
格式:**[0255].[0255].[0255].[0255] ** 例如ipv4:127.0.0.1 (这个地址是本机的ip地址)
即四个0~255的数字组成(在同一个网络中,计算机的IP地址是不允许重复的,都是唯一的)
1.5域名
域名:ip地址的别名,由于ip地址不好记忆,就取了一个好记的别名。
localhost这个域名特指127.0.0.1这IP地址。
localhost = 127.0.0.1 (一样,都表示本机的地址,只是换了一个好记的名称)
域名解析系统:把域名翻译成IP地址的系统
1.6端口
一个IP地址可以有65536个端口(范围是从[0,65535])。
不同的端口被不同的软件占用,以提供不同的服务。
一台电脑可以通过安装多个服务器端软件来提供服务,比如web服务器,ftp服务器…。
仅仅通过ip地址是无法区分不同的服务的,所有需要 IP地址 + 端口号 来区分不同的服务
- 服务器要提供服务必须通过指定的端口
- 服务器与客户端都需要通过端口进行通信
- 端口是可以编程分配的
- 有一些端口是被约定的了
可以通过 小黑窗输入命令: netstat -a -n -o 查看端口的使用情况
1.7协议(http)
制定客户端与服务器之间的通讯规则。不同的协议的作用也不同。
http协议:
-
HTTP(HyperText Transfer Protocol)是超文本传输协议
-
协议双方:浏览器与web服务器都要遵守的协议
-
请求通常是由浏览器发起的
-
HTTP协议中明确规定了 请求数据 和 响应数据 的格式(报文)
-
浏览器 请求 资源 要遵守http协议:请求报文 (请求行,请求头,请求体)
-
浏览器 返回 资源 要遵守http协议:响应报文 (响应行,响应头,响应体)
-
2.用http模块写一个简单的web服务器
2.1用http实现一个简单的虚拟服务器(效果如下)
// 1.引入 http 模块
const http = require('http');
// console.log(http);
// 2.创建服务// request:本次请求// res : 本次响应
const server = http.createServer((req,res)=>{
// 回调函数 : 每一次收到请求,他就执行一次
// 设置响应体
res.setHeader('content-type','text/html;charset=utf-8')
// 结束本次请求
// 设置响应体:返回给用户看的
res.end('你好,虚拟服务器完成');
});
// 3.启动服务
server.listen(8000,()=>{
console.log('虚拟服务器启动成功','端口是8000');
});
运行结果:
2.2操作步骤
-
创建一个文件,名为 http模块实现虚拟服务器.js的文件(文件名路径可以自行设置,建议不要使用中文命名,这里为了演试就用中文的名字)。
-
在js文件中写入如下(如上图效果图)
- 1)引入http核心模块
- 2)使用createServer来创建服务
- 3)使用listener来启动服务
-
运行js代码
在js文件目录,打开小黑窗,键入命令
node http.js
,此时会弹出一个小黑窗,不要关。 -
本地验收
打开一个浏览器页面,输入’http://localhost:8000’,观察效果:
-
共享地址
把localhost改成你自己电脑的ip地址,再把这个路径发你的朋友(同一个局域网)来访问。
-
停止服务( ctrl + c )
2.3工作原理
使用http模块在本机中创建一个虚拟的服务器,用来接收浏览器的请求,并给出响应
注意:小黑窗不要关,它就是服务器,它不会有主动行为(看起来没有任何变化),它在时刻等待客户端的访问。
2.4代码解析
-
引入核心模块,得到的http是一个对象。
-
http.createServer方法创建一个http服务。
参数是一个回调函数:当有http请求进来时,它会自动被调用。
请求一次,它就被调用一次
。第一个参数:
客户端的请求
。第二个参数:
设置对本次请求的响应
。res.end() :设置响应体,结束请求。
-
server.listen() 用来监听端口。
格式:server.listen(端口号,[回调函数])。回调是可选的。
说明:
-
如果监听成功,则回调函数会执行一次。
-
如果不成功(例如端口被占用),会报错。
-
2.5修改代码之后要重启服务器
更改res.end()的内容,重启
后,再次观察
- 停止服务: 在小黑窗中按下ctrl+c 停止服务。
- 重启服务:就是重新运行程序(按下向上的箭头,再回车)。
3.理解请求与响应
3.1请求
当web服务器就绪之后,如果没有客户端来访问,它是不会有任何效果的。那么回调函数就不会被执行了。
然而每一次的请求,都会导致回调函数要执行一次。
3.2服务器的响应内容格式
res.end()的格式只能是 string 或 buffer
4.根据不同的url返回不同的内容-认识URL
4.1URL全称
Uniform Resource Locator,统一资源定位符。
4.2作用
定位资源
4.3格式
协议://主机地址[:端口]/路径?查询字符串#锚点
-
协议:http 或者是 https
-
主机地址:IP地址 或者 域名
-
端口号:
-
http请求,默认端口80(可以省略)
-
https请求,默认端口443(可以省略)
-
MySQL默认端口3306
-
-
路径:服务器文件夹上的资源。(.html/.css/.images/.js/接口)
-
查询字符串(参数):? 后面的部分,是键值对的形式
-
锚点:网页内部的锚点链接
5.不同的URL返回不同的内容-req.url
5.1目标:
通过 req.url来获取当前请求的url地址 ,并做出相应处理
5.2req.url 用来获取本次请求的资源地址。
//引入http模块
const http = require('http');
// 创建服务
const server = http.createServer(function(req, res) {
console.log(req.url)
res.end(req.url)
});
// 启动服务
server.listen(8081, function() {
console.log('success');
});
req.url一定是以**/**开头的。
在现代浏览器中,它们会自动去请求服务器上的favicon.ico
(先不用理这个)
6.不同的URL返回不同的内容-读取文件内容并返回
6.1目标
用户在访问服务器上不同的url时,能返回不同的内容
目录结构
|-index.html
|-style.css
|-01.png
|-js/jquery.js
|-server.js
请求与响应的对应的关系
用户的请求地址 | 服务器的动作 |
---|---|
http://localhost:8000 | 读出index.html的内容并返回 |
http://localhost:8000/index.html | 读出index.html的内容并返回 |
http://localhost:8000/style.css | 读出style.css的内容并返回 |
http://localhost:8000/01.png | 读出01.png的内容并返回 |
http://localhost:8000/js/jquery.js | 读出jquery.js的内容并返回 |
http://localhost:8000/xxxx 或者不是上面的地址 | 返回404 |
代码示例:
// 1.引入 http 模块
const http = require('http');
// console.log(http);
const fs = require('fs')
const path = require('path')
// 2.创建服务
// request:本次请求
// res : 本次响应
const server = http.createServer((req,res)=>{
// 回调函数 : 每一次收到请求,他就执行一次
// 读出文件
// fs.readFile('')
const {url} = req;
console.log(url);
if(url === '/' || url === '/index.html'){
const pathFile = path.join(__dirname,'index.html');
// console.log(pathFile);
// 同步读取文件
const content = fs.readFileSync(pathFile,'utf8');
// console.log(a);
// 结束请求
res.end(content)
} else if(url === '/style.css'){
const pathFile = path.join(__dirname,'style.css');
// console.log(pathFile);
// 同步读取文件
const content = fs.readFileSync(pathFile,'utf8');
// console.log(a);
// 结束请求
res.end(content)
}
else if(url === '/01.jpg'){
const pathFile = path.join(__dirname,'01.jpg');
console.log(pathFile);
// 同步读取文件
const content = fs.readFileSync(pathFile);
console.log(content);
// console.log(content);
// 结束请求
res.end(content)
}
else if(url === '/js/jQuery.js'){
const pathFile = path.join(__dirname,url);
console.log(pathFile);
// 同步读取文件
const content = fs.readFileSync(pathFile);
res.setHeader('content-type','text/html;charset=utf-8')
console.log(content);
// console.log(content);
// 结束请求
res.end(content)
}
else{
res.end('ok')
}
});
// 3.启动服务
server.listen(8000,()=>{
console.log('服务器启动成功');
})
6.2什么是静态资源
静态资源指的是html文件中链接的外部资源,如.html, css、js、image文件等等),服务器的处理方法就是:读出文件内容,返回给用户。
7.不同的URL返回不同的内容-设置content-type
7.1目标
会根据不同的文件类型来设置不同的content-type
7.2content-type的作用
在http协议中,content-type用来告诉对方本次传输的数据的类型是什么。
- 在请求头中设置content-type来告诉服务器,本次请求携带的数据是什么类型的
- 在响应头中设置content-type来告诉服务器,本次返回的数据是什么类型的
通过使用res对象中的setHeader方法,我们可以设置content-type这个响应头。这个响应头的作用是告诉浏览器,本次响应的内容是什么格式的内容,以方便浏览器进行处理。
7.3常见的几种文件类型及content-type
- .html:
res.setHeader('content-type', 'text/html;charset=utf8')
- .css:
res.setHeader('content-type', 'text/css;charset=utf8')
- .js:
res.setHeader('content-type', 'application/javascript')
- .png:
res.setHeader('content-type', 'image/png')
- json数据:
res.setHeader('content-type', 'application/json;charset=utf-8')
其它类型,参考这里:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
7.4代码示例:
目录结构:
|--pubic
|-public/index.html
|-public/stye.css
|-public/1.png
|-server.js
// 1.引入http模块
const http = require('http');
// console.log(http); //输出的一个对象
const path = require('path');
const fs = require('fs');
// - .html:` res.setHeader('content-type', 'text/html;charset=utf8') `
// - .css:`res.setHeader('content-type', 'text/css;charset=utf8')`
// - .js:`res.setHeader('content-type', 'application/javascript') `
// - .png:`res.setHeader('content-type', 'image/png')`
// - json数据:`res.setHeader('content-type', 'application/json;charset=utf-8')`
// 2.创建服务
const server = http.createServer((req, res) => {
// 解构赋值
const { url } = req;
// console.log(url);
// 获取路径
const pathFile = path.join(__dirname, 'public', url);
// console.log(pathFile);
// 获取后缀名
const ext = path.extname(pathFile);
// console.log(ext);
try {
if (ext === '.html') {
res.setHeader('content-type', 'text/html;charset=utf-8')
const conter = fs.readFileSync(pathFile);
res.end(conter);
}else if(ext === '.css'){
res.setHeader('content-type', 'text/css;charset=utf-8')
const conter = fs.readFileSync(pathFile);
res.end(conter);
}
else if(ext === '.js'){
res.setHeader('content-type', 'application/javascript')
const conter = fs.readFileSync(pathFile);
res.end(conter);
}
else if(ext === '.jpg'){
res.setHeader('content-type', 'image/jpg')
const conter = fs.readFileSync(pathFile);
res.end(conter);
}
else{
res.end('404');
}
} catch (err) {
res.statusCode = 404;
res.end("请求不到数据", '404')
}
});
// 3.启动服务
server.listen(8000, () => {
console.log('启动服务器成功', '端口号', 8000);
});
8.不同的URL返回不同的内容-设置statusCode
代码演示:
res.statusCode = 404;
res.end("请求不到数据", '404')
9.处理.html文件的二次请求
从服务器获取html文件之后,如果这个html文件中还引用了其它的外部资源(图片,样式文件等),则浏览器会重新再发请求。
假设在index.html中还引入了 style.css 1.png 或者 .js文件,则:浏览器请求localhost:8000/index.html之后,得到的从服务器反馈的内容,解析的过程中还发现有外部的资源,所以浏览器会再次发出第二次请求,再去请求相应的资源。
10.统一处理静态资源
文件目录:
|-public
|-public/index.html
|-public/stye.css
|-public/1.png
|-server.js
代码演示:
// 1.引入 http 模块
const http = require('http');
// 引入模块
const fs = require('fs');
const path = require('path');
// console.log(http);
const extToContentType = {
'.html': 'text/html;charset=utf-8',
'.css': 'text/css;charset=utf-8',
'.js': 'application/javascript',
'.jpg': 'image/jpg',
}
// 2.创建服务
// request:本次请求
// res : 本次响应
const server = http.createServer((req, res) => {
// 回调函数 : 每一次收到请求,他就执行一次
// const { url } = req;
// console.log(url);
// const pathFile = path.join(__dirname, 'public-content-type', url);
// console.log(pathFile);
// const conter = fs.readFileSync()
// 解构赋值
const { url } = req;
// console.log(url);
// 获取路径
const pathFile = path.join(__dirname, 'public', url);
// console.log(pathFile);
// 获取后缀名
const ext = path.extname(pathFile);
// console.log(ext);
if (extToContentType[ext]) {
// const conter = fs.readFileSync(pathFile);
res.setHeader('content-type', extToContentType[ext])
res.end(conter);
} else {
res.statusCode = 404;
res.end("请求不到数据", '404')
}
});
// 3.启动服务
server.listen(8001, () => {
console.log('服务器启动成功');
})
11.理解静态资源与接口的区别
服务器上有很多的资源,每个资源都有自己的url。客户端浏览器想要访问某个资源就要向服务器发起对应的请求。
11.1资源的分类
- 静态资源
- 它们一般表现为一个一个的文件。例如index.html, style.css, index.js, mp4, .png…。
- 处理请求静态资源时,服务器一般就直接读出资源的内容,再返回给客户端浏览器
- 动态资源:接口
- 它们不是以某个具体的文件存在的,而是服务器上的一段代码,访问接口时,服务器会执行这段代码,然后把代码的执行结果返回给客户端浏览器。
11.2发送请求的途径
- 在地址栏中直接访问这个url
- 通过某个a标签进行进行跳转
- 通过表单进行提交
- 通过ajax技术访问这个url
11.3发送请求的类型
- get:在地址栏中直接访问这个url就是get方式。对于静态资源,我们通过的处理方式就是get请求。
- post: 通过表单提交,可以设置form的method为post
- delete
- put
- patch
- options
- …
12.写一个不带任何参数的get类型接口
12.1目标
提供一个名为getList的接口(http://localhost:8083/getList),它以json字符串格式返回
db/data.json
的内容。
12.2目录结构
|-db
|---data.json # 数据
|-server.js # 你的代码
12.3代码演示
// 三要素
// 1.引入 http 模块
const http = require('http');
// console.log(http);
const path = require('path');
// 引入模块
const fs = require('fs');
// 2.创建服务
// request:本次请求
// res : 本次响应
const server = http.createServer((req, res) => {
// 回调函数 : 每一次收到请求,他就执行一次
// 1. 当你的请求是get类型,并且地址是/getList时,解析查询字符串
// 设置响应体
// res.setHeader('content-type','text/html;charset=utf-8')
const { url, method } = req;
console.log(url, method);
if (url === "/getList" && method === "GET") {
const pathFile = path.join(__dirname, "db", 'data.json');
console.log(pathFile);
res.setHeader('content-type','application/json;charset=utf8')
const conter = fs.readFileSync(pathFile)
res.end(conter);
} else {
res.statusCode = 404;
res.end("404")
}
});
// 3.启动服务
server.listen(8452, () => {
console.log('服务器启动成功');
});
注意:类型
- req.method 可以判断请求的类型
- res.end()的参数只能是字符串(或者是buffer),而不能是对象
13.写一个不带任何参数的get类型接口
13.1目标
提供一个名为getList?name=abc的接口(http://localhost:8083/getList?name=abc),它以json字符串格式返回
db/data.json
的内容。
13.2目录结构
|-db
|---data.json # 数据
|-server.js # 你的代码
13.3代码演示:
// 1.引入 http 模块
const http = require('http');
// console.log(http);
// 引入模块
const fs = require('fs');
const path = require('path');
const ps = require("querystring");
// 2.创建服务
// request:本次请求
// res : 本次响应
const server = http.createServer((req, res) => {
// 回调函数 : 每一次收到请求,他就执行一次
const [url, queryStr] = req.url.split("?");
if (url === "/getList" && req.method === "GET") {
const qsObj = ps.parse(queryStr)
console.log(qsObj);
const pathFile = path.join(__dirname, "db", "data.json")
res.setHeader('content-type', 'application/json;charset=utf8')
const conter = fs.readFileSync(pathFile)
const arr = JSON.parse(conter)
const re = arr.find(function (item) {
if(item.name === qsObj.name){
return true;
}else{
return false;
}
})
const resa = JSON.stringify(re)
console.log(resa);
res.end(resa)
} else {
res.end('你好');
}
// 结束本次请求
// 设置响应体:返回给用户看的
});
// 3.启动服务
server.listen(8004, () => {
console.log('服务器启动成功');
})