服务器相关概念
服务器与客户端
服务器是提供网络服务的机器,通过安装特殊的软件(或者是运行某段特殊的代码)来提供服务。
服务器 = 电脑 + 能给其它电脑/设备提供服务的软件
客户端与服务器:提供服务的是服务器,享受服务的是客户端
服务器的类型
根据服务不同,服务器的类型也不同:
- web服务器。安装apache, tomcat, iis, 或者在nodejs环境写代码 来提供:图片浏览,新闻浏览....等服务的服务器。
- ftp服务器。安装serv-U软件,为其它电脑提供文件下载,共享服务。
- 数据库服务器。安装mysql软件,为其它电脑提供数据库服务。
....
web服务器:
- 用户通过浏览器来享受web服务器提供的服务
- 我们用url地址来访问某个web服务器上的资源
- 浏览器端发起请求,web服务器收到请求后,响应这个请求,并将处理结果返回给浏览器
- 浏览器端与web服务器是通过http(或者是https)协议来进行请求和响应
ip地址
全称:I
nternet P
rotocol Address。
作用:标识一个网络设备(计算机、手机、电视)在某一个具体的网络当中的地址。要访问某个电脑上的资源,先要找到它的ip。
分类:ipV4 ipV6 (www.gov.cn/xinwen/2018…)
格式:[0-255].[0-255].[0-255].[0-255]
即为四个 0-255 的数字组成(以ip4为例)。在同一个网络中,计算机的IP是不允许相同的,都是唯一的。
127.0.0.1 特指本机ip地址。
这个 http://220.181.38.149/ 会指向哪里?
域名
域名:ip地址的别名,由于ip地址不好记忆,我就给它们取个好记的别名。localhost这个域名特指127.0.0.1这个地址。
域名解析系统:把域名翻译成Ip地址的系统。
端口
一个IP地址的端口可以有65536个,范围是从[0,65535])。不同的端口被不同的软件占用,以提供不同的服务。
一台电脑可以通过安装多个服务器端软件来提供服务,比如Web服务、FTP服务、SMTP服务等。显然,仅仅通过ip地址是无法区分不同的服务的,这里就需要用到 “IP地址+端口号”来区分不同的服务
。
理解
如果理解IP地址(一台服务器)是一栋大商场,端口就是商场中的商铺的编号。
如果理解IP地址(一台服务器)是公司的前台电话,端口就是公司中各个部门的分机号。
- 服务器要提供服务必须要通过指定的端口
- 服务器与客户端都需要通过端口要进行通信
- 端口是可以编程分配
- 有一些端口号是被预定了的。
- http: 80
- https:443
- mysql:3306
通过netstat -a -n -o
查看端口使用情况
协议
制定客户端与服务器之间的通讯规则。不同的协议的作用也不同。
http协议:
- HTTP(HyperText Transfer Protocol) 超文本传输协议。
- 协议双方: 浏览器与web服务器
- 请求由浏览器发起的
- HTTP 协议中明确规定了
请求数据
和响应数据
的格式(报文)
-
- 浏览器 请求 资源 要遵守 http 协议: 请求报文(请求行,请求头,请求体)
- 服务器 返回 资源 要遵守 http 协议: 响应报文(响应行,响应头,响应体)
用http 模块写一个简单的web服务器
自己完成的网页,如果让其他人能够访问?
目标
用http模块写一个简单的服务器,让同学来访问本机的服务
要点
- 引入nodejs中的核心模块:http
- 使用createServer来创建服务
- 使用listen方法来启动服务
操作
有三步:
-
- 手写代码,实现服务器功能
-
- 运行代码,启动服务
-
- 访问服务,测试功能
第一步:新建一个文件,名为 d:/src/01http.js
( 文件名及路径名可以自行设置,建议均不使用中文字符), 内容如下
// 1. 引入http模块
const http = require('http');
// 2. 创建服务
const server = http.createServer(function(req, res) {
console.log('有人来访问了')
// 向客户端发送内容,并结束本次响应
res.end('hello world');
});
// 3. 启动服务
server.listen(8081, function() {
console.log('服务器启动成功,请在http://localhost:8081中访问....');
});
第二步:运行js代码,启动服务。
在小黑窗中进入到01http.js所在的目录,键入命令 node 01http.js
,此时会弹出一个小黑窗,不要关。
第三步:测试功能
打开一个浏览器页面,输入地址:http://localhost:8081
,观察效果:
- 浏览器中的效果
- 小黑窗中的效果
停止服务:ctrl + c
拓展
共享让同学来访问
把localhost改成你自己电脑的ip地址,例如:http://192.xxx.xxx.xxx:8081
,再把这个路径发你的同学(同一个局域网)来访问。
如果不能被其他同学访问,有可能你需要手动关闭你自己计算机的防火墙。
工作原理
使用http模块在本机上创建一个虚拟服务器,它来接收浏览器的请求,并给出响应。
注意:
- 小黑窗不要关,它就是服务器
- 服务器本身不会有主动行为(小黑窗看起来没有任何变化),它在时刻等待客户端的访问
- 不要用鼠标选中小黑窗的内容,会导致程序假死
- 修改代码后要重启
-
- 更改res.end()的内容,
重启
后,再次观察。 - 重启服务:就是重新运行程序(按下向上的箭头,再回车)。
- 更改res.end()的内容,
代码解析-理解请求和响应
代码解析
- 引入核心模块,得到的http是一个对象。
- http.createServer方法创建一个http服务。参数是一个回调函数:当有http请求进来时,它会自动被调用。
请求一次,它就被调用一次
。
- 第一个参数:
客户端的请求
。 第二个参数:设置对本次请求的响应
。
- res.end() :设置响应体,结束请求。
- server.listen() 用来监听端口。
- 格式:server.listen(端口号,[回调函数]) 。回调是可选的。 说明:
-
如果监听成功,则回调函数会执行一次。 如果不成功(例如端口被占用),会报错。
理解请求和响应
请求
当web服务器就绪之后,如果没有客户端来访问它,它也是不会有任何效果的。也就是说回调函数不会执行。
而每一次的请求,都会导致回调函数要执行一次。
响应
通过res.end来设置响应的内容,res.end()的格式只是能是buffer或者是String
====做练习====
- 写一个服务器,让你的同学们来访问一下。随机返回内容,让不同的访客看到不一样的内容
const strs = [
"你是我见过的最好的合作伙伴",
"我特别愿意和你一起工作",
"今天天气很好,遇到你很开心"
]
// 1. 引入 http
const http = require('http')
// 2. 创建服务
// 每次收到请求,回调就会执行
const server = http.createServer((request, response) => {
console.log(Date.now(), '有人访问')
// 随机下标
const idx = Math.floor(Math.random() * strs.length)
// 指定浏览器解码字符
response.setHeader("content-type", "text/html;charset=utf8")
response.end(strs[idx])
})
// 3. 启动服务
server.listen(3001, () => {
console.log('服务器启动, 3001端口')
})
- 修改代码中的端口号,开启多台服务器。复制一份代码,并启动,更改端口号,模拟多台服务器。
不同请求返回不同的内容-认识URL
以上的服务器无论用户的请求地址是什么,都只能返回一个固定的内容,这与我们平时上网的效果是不一样的。
全称
Uniform Resource Locator,统一资源定位符。
- 作用:定位资源(css,html,js,png, avi,接口......)
- 格式:协议://主机地址[:端口]/路径?查询字符串#锚点
- 示例:baidu.com:80/schools/stu…
- 协议: http 或者是 https
- 主机地址: IP地址 或者 域名
- 端口号
http请求,默认端口80(可以省略)
https请求,默认端口443(可以省略)
MySQL默认端口3306
- 路径
- 服务器文件夹上的资源。(.html/.css/.images/.js/接口)
- 参数(查询字符串)
- ? 后面的部分,是键值对的形式
- 锚点
- 网页内部的锚点链接
不同请求返回不同的内容-问题分析
思路:在服务器端收到客户端发的请求之后,分析url是什么,然后分别对应处理
不同请求返回不同的内容-req.url
目标
了解 req.url属性
req.url属性
首先就需要知道浏览器请求的url是什么。
涉及到和请求相关的信息,都是通过请求响应处理函数的第一个参数完成的。
代码示例
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用来获取本次请求的资源地址。在请求行中可以看到这一点。
序号 | 浏览器中的url | 服务器中的req.url |
---|---|---|
1 | http://localhost:8080 | / |
2 | http://localhost:8080/a.html | /a.html |
3 | http://localhost:8080/js/jquery.js | /js/jquery.js |
4 | http://localhost:8080/1.jpg | /1.jpg |
5 | http://localhost:8080/api?a=1&b=2 | /api?a=1&b=2 |
小结
- req.url一定是以/开头的
- 在现代浏览器中,它们会自动去请求服务器上的
favicon.ico
不同的URL返回不同的内容-实操
目标
用户在访问服务器上不同的url时,能返回不同的内容
目录结构
根目录
├── css
│ └── index.css
├── img
│ └── bg.jpeg
├── js
│ └── axios.js
├── index.html
└── serve.js # 服务器
请求与响应的对应的关系
用户的请求地址 | 服务器的动作 |
---|---|
http://localhost:8000 | 读出index.html的内容并返回 |
http://localhost:8000/index.html | 读出index.html的内容并返回 |
http://localhost:8000/css/index.css | 读出index.css的内容并返回 |
http://localhost:8000/img/bg.jpeg | 读出图片的内容并返回 |
http://localhost:8000/js/axios.js | 读出axios.js的内容并返回 |
http://localhost:8000/xxxx 或者不是上面的地址 | 返回404 |
示例代码
const http = require('http')
const fs = require('fs')
const path = require('path')
const server = http.createServer((req, res) => {
// 1. 获取url
const { url } = req // req.url 解构赋值
console.log(url)
if(url === '/' || url === '/index.html') {
// 读出文件内容并返回
// 1) 文件的位置
const filePath = path.join(__dirname, 'index.html')
// 2) 读出它的内容
const content = fs.readFileSync(filePath, 'utf8')
console.log(content)
// 3) 返回
res.end(content)
} else if(url === '/css/index.css') {
// 读出文件内容并返回
// 1) 文件的位置
const filePath = path.join(__dirname, 'css/index.css')
// 2) 读出它的内容
const content = fs.readFileSync(filePath, 'utf8')
console.log(content)
// 3) 返回
res.end(content)
} else {
res.end('ok')
}
})
server.listen(8000, ()=>{
console.log('服务器已经在8000启动');
})
综合使用fs
, path
, __dirname
图示
注意
- url地址与服务器上的文件地址并不是一一对应的。
- url的作用是确定用户要访问的资源的位置,在地址栏中输入回车之后,这个请求会到web服务器中来,然后由web服务器来决定此时返回什么数据给用户。但是,我们能够根据url来推测服务器会返回什么信息吗? - 不能!
url:http://nodejs.cn/api/querystring.html
请求一个页面,名是querystring.html
url:http://oa.itcast.cn/seeyon/main.do?method=main
url:https://mail.qq.com/cgi-bin/frame_html?sid=aLqnlljMxF54DgtW&r=d281ced83329f34caae9786fcb5d4934
显然,不能,你能从服务器上获得什么,完全是由服务器决定的。
如果用户请求的是静态资源(静态资源指的是html文件中链接的外部资源,如.html, css、js、image文件等等),服务器的处理方法就是:读出文件内容,返回给用户。
设置content-type
目标
- 理解content-type的作用
- 认识常见的content-type值
- 设置响应头中的content-type
content-type的作用
在http协议中,content-type用来告诉对方本次传输的数据的类型是什么。
- 在请求头中设置content-type来告诉服务器,本次请求携带的数据是什么类型的
- 在响应头中设置content-type来告诉服务器,本次返回的数据是什么类型的
通过使用res对象中的setHeader方法,我们可以设置content-type这个响应头。这个响应头的作用是告诉浏览器,本次响应的内容是什么格式的内容,以方便浏览器进行处理。
常见的几种文件类型及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')
其它类型,参考这里:developer.mozilla.org/en-US/docs/…
如果读出来的是.html的文件,但是content-type设置为了css。则浏览器将不会当作是html页面来渲染了。
格式
res.setHeader('content-type', 值)
示例
const http = require('http')
const fs = require('fs')
const path = require('path')
const server = http.createServer((req, res) => {
// 省略其他
if(url === '/' || url === '/index.html') {
// 读出文件内容并返回
// 省略其他
res.setHeader('content-type', 'text/html;charset=utf8');
res.end(content)
}
}
server.listen(8000, ()=>{
console.log('服务器已经在8000启动');
})
设置statusCode
目标
了解statusCode的作用,会正确使用statusCode
statusCode
就是http请求的状态码。 约定如下
设置格式
res.statusCode = 值
示例
res.statusCode = 301;
// res.setHeader('location','http://www.qq.com')
res.statusCode = 404
res.statusCode = 500
res.end()
处理.html文件中的二次请求
什么是二次请求
从服务器获取html文件之后,如果这个html文件中还引用了其它的外部资源(图片,样式文件等),则浏览器会重新再发请求,这个就是二次请求。
背景
假设在index.html中还引入了 index.css, bg.jpeg 或者 .js文件,则:浏览器请求localhost:8000/index.html之后,得到从服务器反馈的内容(index.html的代码),解析的过程中还发现有外部的资源(图片,样式,js),所以浏览器会再次发出第二次请求,再去请求相应的资源。
根目录
├── css
│ └── index.css
├── img
│ └── bg.jpeg
├── js
│ └── axios.js
├── index.html
└── serve.js # 服务器
思路
一个最朴素的想法是针对所有不同的请求来各自返回不同的文件。
const http = require('http');
const fs = require('fs');
const path = require('path');
//创建服务器
const app = http.createServer((req, res) => {
if (req.url === '/index.html') {
let htmlString = fs.readFileSync(path.join(__dirname, 'index.html'));
res.end(htmlString);
}
else if (req.url === '/style.css') {
let cssString = fs.readFileSync(path.join(__dirname, 'style.css'));
res.setHeader('content-type', 'text/css');
res.end(cssString);
} else if (req.url === '/1.png') {
let pngString = fs.readFileSync(path.join(__dirname, '/1.png'));
res.end(pngString);
} else {
res.setHeader('content-type', 'text/html;charset=utf-8');
res.statusCode = 404;
res.end('<h2>可惜了, 找不到你要的资源' + req.url + '</h2>');
}
});
//启动服务器,监听8082端口
app.listen(8082, () => {
console.log('8082端口启动');
});
Express基本介绍
Express 是一个基于 Node.js 平台,快速、开放、极简的 web 开发框架。
-
框架:是一个半成品,用来快速解决一类问题;库就是工具集,使用非常灵活) (框架有:bootstrap, lay-ui, express, vue, react ; 库:zepto.js , jQuery, day.js, underscore, lodash, art-template, axios, echart.....)
-
web 开发: 对不同的请求能够显示页面;提供接口服务; 参考链接
-
我们前面用http模块来支持web服务,现在要用express来写web服务
-
对于node.js来说,Express 是一个第三方模块,有丰富的 API 支持,强大而灵活的中间件特性
-
Express 不对 Node.js 已有的特性进行二次抽象,只是在它之上扩展了 Web 应用所需的基本功能
理解:中间件
- 给用户提供更好的服务
- 可方便的拆卸
运行第一个express程序
expresss 是一个第三方模块(在npm上可以下载),在使用它之前要先去下载它,在下载包之前要先创建项目,并通过npm init 创建package.json文件。
创建项目并初始化
创建一个全新的文件夹,假设名字为 learn-express(目录名不要有汉字,也不要某个包的名字),在此目录下运行npm init -y
命令来生成package.json文件
下载express包
参考文档:expressjs.com/en/starter/…
与安装其他的第三方包一致,本地安装
npm i express
注意:
- 项目目录名字不要取中文,也不要取为
express
- 如果安装不成功:
-
- 换个网络环境
- 运行下
npm cache clean -f
,再重新运行下载命令试试
快速创建web服务器
参考文档:expressjs.com/en/starter/… 在项目根目录下新建一个js文件,例如app.js,其中输入代码如下:
// 0. 加载 Express
const express = require('express')
// 1. 调用 express() 得到一个 app
// 类似于 http.createServer()
const app = express()
// 2. 设置请求对应的处理函数
// 当客户端以 GET 方法请求 / 的时候就会调用第二个参数:请求处理函数
app.get('/', (req, res) => {
res.send('hello world')
})
// 3. 监听端口号,启动 Web 服务
app.listen(3000, () => console.log('app listening on port 3000!'))
说明:
- app.get('/')相当于添加事件监听:当用户以get方式求"/"时,它后面的回调函数会执行,其回调函数中的req,res与前面所学http模块保持一致。
- res.send()是exprss框架给res对象补充提供的方法(http模块中的res是没有这个方法的),用于结束本次请求。类似的还有res.json(), res.sendFile() 。
- express 框架会增强req,res的功能
托管静态资源-web服务器
参考文档:expressjs.com/en/starter/…
让用户直接访问静态资源是一个web服务器最基本的功能。
根目录
├── public
│ ├── css
│ │ └── index.css
│ ├── img
│ │ └── bg.jpeg
│ ├── js
│ │ └── axios.js
│ └── index.html
└── serve.js # 服务器
例如,如上url分别是请求一张图片,一份样式文件,一份js代码。我们实现的web服务器需要能够直接返回这些文件的内容给客户端浏览器。
在前面学习http模块时,我们已经实现了这些功能了,但是要写很多代码,现在使用express框架,只需一句代码就可以搞定了,这句代码是 express.static('public')
忽略前缀
// 加载 Express
const express = require('express')
// 1. 调用 express() 得到一个 app
// 类似于 http.createServer()
const app = express();
// 2. 设置请求对应的处理函数
app.use(express.static('public'))
// 3. 监听端口号,启动 Web 服务
app.listen(3000, () => console.log('app listening on port 3000!'))
此时,所有放在public下的内容可以直接访问,注意,此时在url中并不需要出现public这级目录。在public下新建index.html,可以直接访问到。
限制前缀
// 限制访问前缀
app.use('/public', express.static('public'))
这意味着想要访问public下的内容,必须要在请求url中加上/public
===练习===
路由和接口
参考文档:expressjs.com/en/starter/…
路由(Routing)是由一个 URL(或者叫路径标识)和一个特定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何处理响应客户端请求。每一个路由都可以有一个或者多个处理器函数,当匹配到路由时,这些个函数将被执行。
格式
const app = express();
// 定义路由
app.METHOD(PATH, HANDLER)
其中:
app
是 express 实例 。(const app = express())METHOD
是一个 HTTP 请求方法。 全小写格式。如:post,get,delete等PATH
是请求路径(相当于在http模块中用到过的url.parse(req.url).pathname
)
浏览器url | 服务端路径 |
---|---|
http://localhost:8080 | / |
http://localhost:8080/public/a/index.html | /public/a/index.html |
http://localhost:8080/index.html?a=1&b=2 | /index.html |
HANDLER
是当路由匹配到时需要执行的处理函数。(req,res)=>{ }
写接口-整体说明
接口文档谁来定?
提问:接口是前端,还是后端来定?
接口传参
我们使用ajax请求向服务器接口传参,按http协议的约定,每个请求都有三个部分:
- 请求行: 保存了请求方式,地址,可以以查询字符串的格式附加一部分数据。
- 请求头:它可以附加很多信息,其中content-type用来约定请求体中保存的数据格式。
content-type常见有三种取值:
content-type的值 | 表示请求体的数据格式 | 示例 |
---|---|---|
application/x-www-form-urlencode | 普通键值对象 | a=2&c=1 |
application/json | json对象 | {a:1,b:{c:1}} |
multipart/form-data | 上传文件 | file |
- 请求体: 本次请求携带的参数。至于这些参数到了后端应该如何解析出来,由请求头中的content-type来决定。
- 方法一:请求行。常见方式如下:
-
- 使用ajax技术,通过get方式传参。
- 在浏览器地址栏中输入接口地址并补充上查询字符串。
- 方法二:请求体
-
- ajax中的post, put, delete可以从请求体中进行传参。
另外,请求头中的content-type用来告之服务器应该以何种方式去解析请求体中的数据。
express写get接口
get无参数
const express = require('express');
const app = express();
app.get('/get', function(req, res) {
// 直接返回对象
res.json({ name: 'ceshi' });
});
app.listen('8088', () => {
console.log('8088');
});
注意:
- res.json()是express提供的方法,同时会结束请求(类似于res.end)。
get接口有参数
express框架会自动收集get类型的接口从url地址中传递的查询字符串参数,并自动保存在req对象的query
属性中。我们直接来获取即可。
const express = require('express');
const app = express();
app.get('/get', function(req, res) {
// 直接返回对象
console.log(req.query);
res.send({ name: 'abc' });
});
app.listen('8088', () => {
console.log('8088');
});
注意:req.query属性是express框架额外提供的属性。
post接口-普通键值
post接口与get请求不同在于:它的参数一般是通过请求体来传递的。根据传递的参数的格式不同,分成三种情况来说
- 传递普通键值对
- 传递form表单(涉及文件上传)
- 传递json
普通键值对参数
具体来说当请求头的content-type为x-www-form-urlencoded时,表示上传的普通简单键值对 。
步骤
// 1. 使用中间件
app.use(express.urlencoded());
app.post("/add",function(req,res){
// 2. 可以通过req.body来获取post传递的键值对
// res.json是express提供的一个函数,用来返回一个json数据给客户端,同时会结束请求
// 类似于res.end, res.send()
res.json(req.body)
})
注意:
- app.use(....)之后,在res.body中就会多出一个属性res.body。
extended: false
:表示使用系统模块querystring来处理传入的参数,也是官方推荐的extended: true
:表示使用第三方模块qs来处理传入的参数.
post接口-json格式的参数
在post传递参数时,如果要传入的参数比较复杂(多级嵌套),则可以使用json格式上传。
var data = {
name:"abc",
address:{
"a":1,
"b":2,
"info":"c"
}
}
后端
app.use(express.json());
// 会自动加入req.body属性,这个属性中就包含了post请求所传入的参数
// 用来处理JSON格式的数据
app.post('/postJSON',(req,res)=>{
// 后端收到post传参
console.log(req.body);
res.send('/postJSON')
})
post接口-form-data文件上传
如果post涉及文件上传操作,则需要在服务器端额外使用第三方multer
这个包(不属于express)来获取上传的信息。
Multer 是一个 node.js 中间件,用于处理 multipart/form-data
类型的表单数据,它主要用于上传文件。
enctype="multipart/form-data"
步骤
1.安装包
npm install multer
2.使用
// 1. 引入包
const multer = require('multer');
// 2. 配置
const upload = multer({dest:'uploads/'}) // 上传的文件会保存在这个目录下
// uploads表示一个目录名,你也可以设置成其它的
// 3. 使用
// 这个路由使用第二个参数 .upload.single表示单文件上传, 'cover' 表示要上传的文件在本次上次数据中的键名。对应于前端页面上的:
// <input type="file" name='cover'/>
app.post("/postfile",upload.single('cover'), function(req,res){
// req.file 记录了文件上传的信息
// req.body 记录了其它普通参数(非文件)的信息
// 其它操作
})
说明:
- 如果当前目录下没有uploads,它会自动创建uploads这个文件夹
upload.single
只是处理了文件的上传。你仍可以通过req.body来获取其它参数
后端框架代码
传参方式 | 前端 content-type | 后端框架express |
---|---|---|
请求行 | get方式 | req.query |
请求体 | application/x-www-form-urlencode | app.use(express.urlencoded()); req.body |
请求体 | application/json | app.use(express.json() ); req.body |
请求体 | multipart/form-data | 1. 引入包 const multer = require('multer'); 2. 配置app.post('/apiname', upload.single() , req.body) |
接口传参-整体示例
目录结构
根目录
├── public
│ ├── js
│ │ └── axios.js
│ └── api.html # 通过axios.js发请求调用接口
└── app.js # 提供接口
要求:
- localhost:3000/api.html。l可以访问public下的api.html文件
- 在后端实现四个接口,分别来处理在api.html中发出的请求
前端
用axios来发请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="btn1_get">接口测试1:get请求带参数</button>
<button id="btn2_post"> 接口测试2:post-传递普通键值对</button>
<hr/>
<button id="btn3_postJSON">接口测试3:post-传递json</button>
<hr/>
<form id="myform">
<input type="text" name="title">
<input type="file" name="cover">
</form>
<button id="btn4_formdata">接口测试4:post-传递formdata</button>
<hr/>
<script src="./js/axios.js"></script>
<script>
document.getElementById('btn1_get').addEventListener('click',() => {
axios.get('http://localhost:3000/getapi', {params: {a:1,b:2}})
})
var obj = {
"name":"abc",
"address":{
"a":1,
"b":2,
"info":"c"
}
}
document.getElementById('btn2_post').addEventListener('click', () => {
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('http://localhost:3000/post', params, {
headers: {"content-type":"application/x-www-form-urlencoded"}})
})
document.getElementById('btn3_postJSON').addEventListener('click', () => {
axios.post('http://localhost:3000/postJSON', obj)
})
document.getElementById('btn4_formdata').addEventListener('click', () => {
console.log(1)
var fd = new FormData(document.getElementById('myform'));
axios.post('http://localhost:3000/publish',
fd
)
})
</script>
</body>
</html>
后端
// 实现get接口
const express = require('express')
const app = express();
app.use(express.static('public'))
// 引入bodyParse包
const bodyParser = require('body-parser')
// 使用包. 则在后续的post请求中
// 会自动加入req.body属性,这个属性中就包含了post请求所传入的参数
// 处理普通的键值对格式
// Content-Type: application/x-www-form-urlencoded
app.use(express.urlencoded())
// 处理JSON格式
// Content-Type: application/json;
app.use(express.json())
// 引入multer包
const multer = require('multer');
// 配置一下multer
// 如果本次post请求涉及文件上传,则上传到uploads这个文件夹下
// Content-Type: multipart/form-data;
var upload = multer({ dest: 'uploads/'})
// 实现接口1: get类型接口
// 返回所传入的参数,并附上上时间戳
app.get('/getapi',(req,res)=>{
// 通过 req.query快速获取传入的参数
console.log(req.query);
let obj = req.query
obj._t = Date.now();
res.json( obj )
})
// 实现接口2:普通post 键值对
app.post('/post',(req,res)=>{
// 希望在后端收到post传参
console.log(req.body);
let obj = req.body
obj._t = Date.now();
res.json(obj)
})
// 实现接口3:用来JSON格式的数据
// Content-Type: application/json;
app.post('/postJSON',(req,res)=>{
// 希望在后端收到post传参
console.log(req.body);
// res.send('/postJSON')
res.json( req.body )
})
// 实现接口4:接口formDate
app.post('/publish',upload.single('cover'),(req,res)=>{
console.log('publish...')
//upload.single('cover')
// 这里的cover就是在页面中表单元素中的name
// <input type="file" name="cover" />
// 把要上传文件放在指定的目录
console.log(req.file);
// 其它参数,还是在req.body中找
console.log(req.body);
res.json({code:200,msg:'上传成功',info:req.file.path})
})
app.listen(3000,()=>{
console.log('express应用在3000端口启动了');
})
拓展介绍-RESTful接口(了解)
网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备…)。因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致API构架的流行,甚至出现"APIFirst"的设计思想。RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。
REST(Representational State Transfer)表述性状态转换,REST指的是一组架构约束条件和原则。 如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。REST本身并没有创造新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力, 更好地使用现有Web标准中的一些准则和约束。
符合REST规范的设计,我们称之为RESTful设计。 它的设计哲学是将服务器端提供的内容实体看作一个资源,并表现在url上。
普通接口设计
例如:
接口名:localhost:8080/getarticle
类型:get
功能:获取文章信息
接口名:localhost:8080/addarticle
类型:post
功能:添加新文章
接口名:localhost:8080/delarticle
类型:post
功能:删除文章
接口名:localhost:8080/updatearticle
类型:post
功能:编辑文章
//------------下面是普通的api设计---------------
app.get('/getarticle',(req,res)=>{
res.send('获取')
})
app.post('/addarticle',(req,res)=>{
res.send('添加')
})
app.post('/delarticle',(req,res)=>{
res.send('删除')
})
app.post('/updatearticle',(req,res)=>{
res.send('编辑')
})
RESTful接口设计
大佬一般都在用, 懂我意思吧 区别上述功能,主要依靠接口名称和请求类型而在restful设计中,它们应该是这样的:
接口名:localhost:8080/articles
类型:get
功能:获取文章信息
接口名:localhost:8080/articles
类型:post
功能:添加新文章
接口名:localhost:8080/articles
类型:delete
功能:删除文章
接口名:localhost:8080/articles
类型:put
功能:编辑文章
RESTful设计是:
- 通过URL设计资源。接口名一般都是名词,不包含动词。
- 请求方式(get,post,delete,put)决定资源的操作类型
参考代码
const express = require('express')
const app = express();
app.get('/articles',(req,res)=>{
res.send('获取')
})
app.post('/articles',(req,res)=>{
res.send('添加')
})
app.delete('/articles',(req,res)=>{
res.send('删除')
})
app.put('/articles',(req,res)=>{
res.send('编辑')
})
app.listen(8080,()=>{
console.log(8080);
})