HTTP请求的基本过程:
- 浏览器端向服务器端发送HTTP请求(请求报文)
- 后台服务器接收到请求后,处理请求,向浏览器端返回HTTP响应(响应报文)
- 浏览器端接收到响应,解析显示响应体或调用响应回调函数
第一章:HTTP请求
一、原生XHR(xhr请求使用浏览器中遵守同源策略的Ajax引擎实现)🔺
AJAX
- AJAX全称为Asynchronous Javascript And XML,就是异步的JS和XML
- 通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:页面无刷新获取数据
- AJAX不是新的编程语言,而是将现有的标准组合在一起使用的新方式
- 原生xhr和原生fetch都可以发送Ajax请求
AJAX的优点
- 可以无需刷新页面而与服务器端进行通信
- 允许你根据用户事件来更新部分页面内容
AJAX的缺点
- 没有浏览历史,不能回退
- 存在跨域问题
- SEO(搜索引擎优化)不友好
AJAX核心对象
"XMLHttpRequest"👉AJAX的所有操作都是通过该对象进行的
流程
<button id="btn">点我发送请求(原生js-ajax-get)</button>
<div id="content"></div>
<script type="text/javascript">
const btn = document.getElementById('btn');
const content = document.getElementById('content');
let isLoading
//给按钮绑定监听
btn.onclick = ()=>{
// if(isLoading) xhr.abort() // 避免多次请求
// 1. 创建XHR实例对象
const xhr = new XMLHttpRequest();
// xhr内部有5种状态,值分别为: 0、1、2、3、4
// 绑定监听:xhr实例对象在实例出来状态是0, 收到返回数据状态为4
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response);
content.innerHTML = `<h3>${xhr.response}</h3>`;
}
}
}
// 2. GET方式:指定method、url、携带params(服务端路径占位符/:name)或query参数
xhr.open('GET', 'http://127.0.0.1:8080/test_get?name="张三"&age=18');
// 3. 发送请求
xhr.send();
// is isLoading = true
}
</script>
// POST方式:指定method、url、携带params、query或body(主要)参数
xhr.open('POST', 'http://127.0.0.1:8080/test_post')
// 务必要带请求体类型(编码形式):urlencoded或json(application/json)
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
// 请求体携带:
xhr.send('name=张三&age=18') // const p = {name:"张三", age:18}; xhr.send(JSON.stringify(p));
xhr其他配置(API)
// responseType 用于指定返回数据的格式(解析方式)
xhr.responseType = 'json'
// 配置出错回调
xhr.onerror = ()=>{
console.log("请求出错了!")
}
// 设定超时时间
xhr.timeout = 2000
// 配置超时回调
xhr.ontimeout = ()=>{
console.log("请求超时了!")
}
缺点:代码繁琐
二、跨域
JSONP(JSON with Padding)解决跨域🔺
利用不受同源策略CORS限制的script标签访问跨域链接(仅支持get方式),绕过有跨域限制的xhr 后端:
app.get('/test_jsonp', (request, response)=>{
const {callback} = request.query
const person = [{name:'tom', age:18}, {name:'张三', age:18}]
response.send(`${callback}(${JSON.stringify(person)})`) // js对象转换成json字符串
})
前端:
<button id="btn">点我获取数据</button>
<script>
const btn = document.getElementById('btn')
btn.onclick = ()=>{
// 1.创建script节点
const scriptNode = document.createElement('script')
// 2.给节点指定src属性(请求地址)(可使用query参数传递函数名)
scriptNode.src = 'http://localhost:8080/test_jsonp?callback=demo'
// 3.将节点放入页面
document.body.appendChild(scriptNode)
window.demo = (a)=>{
console.log(a);
}
// 4.请求完毕,移除节点
document.body.removeChild(scriptNode)
}
</script>
cors中间件后端express解决跨域
- 后端配置setHeader()跨域响应头方法:
- 简单请求(get; post):
app.get('/test_get ',(request, response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
response.setHeader('Access-Control-Expose-Headers' ,'*')
response.send('hello_test_get')
})
- 复杂请求(put; delete 这两种请求会有预请求options/嗅探请求):
// 预请求处理
app.options('/test_put', (request, response)=>{
// *通配符,可替换为指定前端请求源地址
response.setHeader('Access-Control-Allow-Origin','*')
response.setHeader('Access-Cpntrol-Expose-Headers','*')
response.setHeader('Access-Control-Allow-Methods','*')
response.send()
})
app.put('/test_put', (request, response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
response.setHeader('Access-Control-Expose-Headers','*')
response.send('hello_test_put')
})
- 后端使用cors处理跨域:
const cors = require('cors')
const app = express()
app.use(cors()) // 使用中间件处理跨域
三、jQuery(封装Ajax/依赖于XHR)(一般http请求:非Ajax请求)
完整版
<script>
const btn1 = $('#btn1')
const btn2 = $('#btn2')
const content = $('#content')
btn1.click(()=>{
// 使用jQuery发送ajax-get请求(完整版)
$.ajax({
url: 'http://127.0.0.1:8080/jquery_get', // 请求地址
method: 'GET', // 请求方式
data: {school: 'atguigu'}, // 携带的数据
dataType: 'json', // 配置响应数据格式
timeout: 200, // 超时时间
success: (result, reponseText, xhr)=>{
content.append(<div>姓名: ${result.name}, 年龄: ${result.age}</div>)
}, // 成功的回调
error: ()=>{console.log("请求出错了!")} // 失败的回调
})
})
</script>
精简版
$.get('http://127.0.0.1:8080/jquery_get', {school: 'atguigu'}, (data)=>{
console.log(data) // 成功的回调;
},'json')
缺点:回调地狱问题(需借助Promise解决)
$.get('http://127.0.0.1:8080/jquery_get_1', {school_1: 'atguigu1'}, (data)=>{
console.log(data) // 成功的回调;
$.get('http://127.0.0.1:8080/jquery_get_2', {school_2: 'atguigu2'}, (data)=>{
console.log(data) // 成功的回调;
$.get('http://127.0.0.1:8080/jquery_get_3', {school_3: 'atguigu3'}, (data)=>{
console.log(data) // 成功的回调;
},'json')
},'json')
},'json')
封装jsonp跨域
<script>
const btn = $('#btn')
btn.click(()=>{
$.getJSON('http://localhost:8080/test_jsonp?callback=?',{参数},(data)=>{
console.log(data);
})
})
</script>
四、axios(基本promise封装XHR的异步Ajax请求库)
前端流行的Ajax请求库,react/vue都推荐使用axios发Ajax请求
axios特点:
- 基本promise的异步Ajax请求库
- 浏览器端/node端都可以使用
- 支持请求/响应拦截器
- 支持请求取消
- 请求/响应数据转换
- 批量发送多个请求
<!--
1.axios调用的返回值是Promise实例
2.成功的值叫response,失败的值叫error
3.axios成功的值是一个axios封装的response对象,服务器返回的数据在response.data中
-->
<button id="btn1">获取</button>
<script type= "text/javascript">
// 获取按钮
const btn1 = document.getElementById('btn1')
// 发送GET请求不携带参数
btn1.onclick = ()=>{
const result = axios({
url:'http://localhost: 5000/persons', // 请求地址
method: 'GET', // 请求方式
)}
result.then(
response => {console.log('请求成功了', response.data);},
error => {console.log('请求失败了', error);}
)
}
四、原生Fetch(ES6)(基本promise封装的非xhr的Ajax请求)
浏览器端发请求: 只有XHR或fetch发出的才是ajax请求其它所有的都是非ajax请求🔺
fetch是一个原生函数API,不再使用XmlHttpRequest对象提交ajax请求
Fetch符合关注分离:1. fetch().then先接收请求状态 → 2. 后获取结果数据response.json
原版:
fetch(url,{
method: “POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json"
credentials: "same-origin'
}).then(function(response) {
response.status
response.statusText
response.headers
response.url
return response.text( )
}, function(error) {
error.message
})
简化1:
fetch(/api/search?q=${keyWord})
.then(
response => {
console.log('联系服务器成功了');
return response.json()
}
).then(
response => {console.log('获取数据成功了',response);}
).catch(
(error)=>{conso1e.1og(error);}
)
简化2:
async()=> {
try {
const response= await fetch(/api/search?q=${keyWord}) // 得到Promise状态
const data = await response.json() // 提取响应数据
console.log(data);
} catch (error) {
console.log('请求出错',error);
}
}
第二章:相关内容
http状态码
分类
- 1xx:服务器已经收到了本次请求,但是还需要进一步的处理才可以
- 2xx:服务器已经收到了本次请求,且已经分析、处理等,最终处理完毕
- 3xx:服务器已经接收到了请求,还需要其他的资源,或者重定向到其他位置,甚至交给其他服务器处理
- 4xx:一般指请求的参数或者地址有错误,出现了服务器无法理解的请求(一般是前端的问题)
- 5xx:服务器内部错误(不是因为请求地址或者请求参数不当造成的),无法响应用户请求(一般是后端人员的问题)
常见的状态码
- 200:成功
- 301:重定向,被请求的旧资源永久移除了(不可以访问了),将会跳转到一个新资源,搜索引擎在抓取新内容的同时也将旧的网址重定向为新网址
- 302:重定向,被请求的旧资源还在(仍然可以访问),但会临时跳转到一个新资源,搜索引擎会抓取新的内容而保留旧网址
- 304:请求资源重定向到缓存中(命中了协商缓存)
- 404:资源未找到,一般是客户端请求了不存在的资源
- 500:服务器收到了请求,但是服务器内部产生了错误
- 502:连接服务器失败(服务器在处理一个请求的时候,或许需要其他的服务器配合,但是联系不上其他的服务器了
API分类
1.REST API(restful风格的API)
①发送请求进行CRUD哪个操作由请求方式来决定 ②同一个请求路径可以进行多个操作 ③请求方式会用到GET/POST/PUT/DELETE
const app = express()
app.get('/person', (req,res)=>{
res.send('数据接收!')
})
app.post('/person',(req,res)=>{
res.send('添加数据')
})
app.put('/person',(req,res)=>{
res.send('修改数据')
})
app.delete('/person',(req,res)=>{
res.send('删除数据')
})
app.listen(8090, (error)=>{
if(!error) console.log('服务器开启');
else console.log(err);
})
2.非REST API (restless风格的API)
①请求方式不决定请求的CRUD操作 ②一个请求路径只对应一个操作 ③一般只有GET/POST
const app = express()
app.get('/get_person',(req,res)=>{
res.send('数据接收!')
})
app.post('/add_person',(req,res)=>{
res.send('添加数据')
})
app.post('/update_person',(req,res)=>{
res.send('修改数据')
})
app.post('/delete_person',(req,res)=>{
res.send('删除数据')
})
app.listen(8090, (error)=>{
if(!error) console.log('服务器开启');
else console.log(err);
})
HTTP1.1请求方式与请求参数
请求方式
- GET(简单请求 索取): 从服务器端读取数据→查(R)
- POST(简单请求 提交): 向服务器端添加新数据→增(C)
- PUT(复杂请求 修改): 更新服务器端已存在的数据→改(U)
- DELETE(复杂请求 删除): 删除服务器端数据→删(D)
- HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
- CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
- OPTIONS(复杂请求put和delete发送前携带的嗅探请求)允许客户端查看服务器的性能
- TRACE 回显服务器收到的请求,主要用于测试或诊断
请求参数
-
query 参数(查询字符串参数)
- 参数包含在请求地址中,格式为: http://localhost:0000?name=tom&age=18
- 敏感数据不要用query参数,因为参数是地址的一部分,比较危险
- query参数又称“查询字符串参数”,编码方式为unlencoded
-
params 参数
- 参数包含在请求地址中,格式为: http://localhost:0000/add_person/tom/18
- 敏感数据不要用params参数,因为参数是地址的一部分,比较危险
-
请求体参数
- 参数包含在请求体中,可通过浏览器开发工具查看
- 常用的两种格式:
- 格式一: urlencoded格式👉 例如: hame=tom&age=18👉 对应请求头Content-Type: application/x-www-form-urlencoded
- 格式二: json格式👉 例如: {"name:"tom", "age": 12)👉 对应请求头: Content-Type: application/json 特别注意: GET请求不能携带请求体参数,因为GET请求没有请求体