AJAX新版学习大纲
AJAX 入门
AJAX 简介
- AJAX全称为Asynchronous Javascript And XML,就是异步的 JS 和 XML。
- 通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:页面无刷新获取数据。
- AJAX不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
- ajax也是属于原生js的http请求,可以说是一种特殊的http请求。
在以往提交表单一般是这样子
<body>
<form action="https://www.baidu.com">
用户名:<input type="text" name="username">
密码:<input type="password" name="pad">
<!-- button按钮会触发表单的提交 -->
<button type="submit">登录</button>
</form>
</body>
XML简介
XML:可扩展标记语言
XML:被设计用来 传输和存储数据
比方说客户端(client)与 服务器(serve)前后台进行数据交互的时候,你想获取十条新闻,服务器就要给你十条新闻,那么关键是用的什么方式给你?
于是服务器可以用XML这种字符串形式给你,XML本质就是字符串,不过有很多的规矩。
XML和HTML类似都是可扩展的标记语言,不同点:HTML中都是预定义标签,XML中没有预定义标签,全是自定义标签,用来表示一些数据
例:用xml表示学生数据 <student> <name>孙悟空</name> <age>18</age> <gender>男</gender> </student> 可以发现体积较大了
现在已被JSON取代
例:用JSON表示学生数据 {"name":"孙悟空","age":18,gender:"男"}
AJAX 的特点
AJAX 的优点
- 可以 **无需刷新页面与服务端进行通信 **获取数据
- 允许你根据用户事件来更新部分页面内容(例如淘宝鼠标移动到某个区域页面不刷新,但是部分区域内容更新)
AJAX 的缺点
- 没有浏览历史,不能回退
- 存在跨域问题(同源)–面试高频问题
- SEO不友好(爬虫获取不到信息)
AJAX 的使用
核心对象:XMLHttpRequest
AJAX的所有操作都是通过该对象进行的
搭建测试ajax的服务器
新建任意名的文件夹(最好不用数字开头,不能有大写字母)
接着使用 yarn init (或者 npm init)
将当前项目文件夹变成符合npm规范的包
使用 yarn express
安装express
项目文件夹下新建一个serve.js用来当作服务器
// 1. 引入express
const express = require('express')
// 2.创建一个app实例对象
const app = express()
// 4.配置一个路由 (比如想响应get请求,就起一个 'test_get' 的名字 ,里面有两个对象,请求和响应)
app.get('/test_get',(request,response)=>{
// 函数体
response.send('hello_test_get!!!')
})
// 3.绑定监听 端口号(一般4位数字) + 回调(err是错误对象,如果没有错误对象就证明服务器开启成功)
app.listen(8080,(err)=> {
if(!err) console.log('测试ajax请求的服务器开启成功了');
})
启动服务器(三种方式):node serve / nodemon .\serve.js / 使用第三方插件 Code Runner(右键 点击Run Code开启,快捷键 ctrl+alt+m 关闭服务)
浏览器地址栏输入查看:localhost:8080/test_get (浏览器默认是get请求)
ajax小试牛刀
ajax也是属于原生js的http请求,可以说是一种特殊的http请求。
项目根目录新建文件夹src,下新建 ‘1_ajax小试牛刀.html’文件,右键文件使用vscode的Live Server打开
//...
<style>
#content {
width: 300px;
height: 100px;
border: 1px solid black;
margin-top: 10px;
}
</style>
</head>
<body>
<h3>该页面是测试:ajax小试牛刀</h3>
<button id="btn">点我发送请求(原生js里的ajax的GET请求)</button>
<div id="content"></div>
<script type="text/javascript">
// 获取按钮
const btn = document.getElementById('btn')
// 给按钮绑定监听
btn.onclick = () => {
// 发送ajax请求 有如下几步:
// 1.创建xhr实例对象
const xhr = new XMLHttpRequest()
// 2.指定发送请求的:method、url
xhr.open('GET','http://localhost:8080/test_get')
// 3.发送请求
xhr.send()
}
</script>
</body>
</html>
当点击按钮后控制台会报错,出现经典的跨域问题。(如果提示有…the serve responded with a status of 404 :5050/favicon.ico:1 (Not Found) 那么需要找一个ico图片放到项目文件根目录下即可)
解决跨域:
服务器中暴露静态资源
// 1.引入express
const express = require('express')
// 2.创建app实例对象
const app = express()
// 5.解决跨域:暴露静态资源
app.use(express.static(__dirname+'/src'))
// 4.配置一个路由 (比如想响应get请求,就起一个 'test_get' 的名字 ,里面有两个对象,请求和响应)
app.get('/test_get',(request,response)=>{
// 函数体
// 这里设置一句话,检查是否有人请求了
console.log('有人请求test_get了');
response.send('hello_test_get!!!')
})
// 3.监听
app.listen(8080,(err)=> {
if(!err) {
console.log('测试ajax请求的服务器开启成功了!测试地址如下');
console.log('http://127.0.0.1:8080/1_ajax小试牛刀.html');
}
})
在html文件中将发送请求的url改成 ‘ http://127.0.0.1:8080/test_get ‘,然后不使用vscode的Live Server打开,而是复制到浏览器使用serve.js的 ‘http://127.0.0.1:8080/1_ajax小试牛刀.html’ 地址,同时要看到请求是否成功需要借助xhr的状态state来将xhr.response的结果返回给div中
<h3>该页面是测试:ajax小试牛刀</h3>
<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')
// 给按钮绑定监听
btn.onclick = () => {
// 发送ajax请求 有如下几步:
// 1.创建xhr实例对象
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = ()=> {
if(xhr.readyState === 4) {
console.log(xhr.response);
content.innerHTML = `<h3>${xhr.response}</h3>`
}
}
// 2.指定发送请求的:method、url
xhr.open('GET','http://127.0.0.1:8080/test_get')
// 3.发送请求
xhr.send()
}
</script>
</body>
</html>
xhr的5种状态(了解)
复制’1_ajax小试牛刀.html’文件,改名为‘2_xhr的5种状态.html’,其他步骤和1文件类似方法打开
注意服务器需要再写一行
//方便复制
// 4.监听
app.listen(8080,(err)=> {
if(!err) {
console.log('测试ajax请求的服务器开启成功了!测试地址如下');
console.log('http://127.0.0.1:8080/1_ajax小试牛刀.html');
console.log('http://127.0.0.1:8080/2_xhr的5种状态.html'); //方便复制
}
})
页面html文件代码如下:
//...
<h3>该页面是测试:xhr的5种状态.html</h3>
<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')
// 给按钮绑定监听
btn.onclick = () => {
// 发送ajax请求 有如下几步:
// 1.创建xhr实例对象
const xhr = new XMLHttpRequest()
// xhr实例对象在实例出来的那一刻就是0,随着请求变化不断变化
/*
xhr内部有5种状态,5种状态值分别为:0、1、2、3、4
0:实例出来的那一刻就是0,初始状态
1:open已经调用,但是send没有调用,此时可以修改请求头内容
2:send已经调用了,已经无法修改请求头
3:已经回来部分数据,小的数据会在此阶段一次性接收完毕,较大的数据有待进一步接收,响应头回来了.
4:数据全部接收完毕
// getAllResponseHeaders获取所有响应头
*/
xhr.onreadystatechange = ()=> {
if(xhr.readyState === 1) {
// xhr的请求头api setRequestHeader //配置请求头:请求头中增加 key:value
// xhr.setRequestHeader('demo',123)
// alert('@')
}
if(xhr.readyState === 2) {
// xhr.setRequestHeader('demo',123) //配置请求头:报错 因为2阶段无法修改请求头了
}
if(xhr.readyState === 3) {
console.log('3时接收到的数据',xhr.response);
console.log('3时接收到的响应头',xhr.getAllResponseHeaders());
}
if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)) {
console.log(xhr.response);
content.innerHTML = `<h3>${xhr.response}</h3>`
}
}
// 2.指定发送请求的:method、url
xhr.open('GET','http://127.0.0.1:8080/test_get')
// 3.发送请求
xhr.send()
}
</script>
</body>
</html>
注意:请求成功的判断最好详细一点
if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
//......
}
ajax的get请求(掌握)
复制’2_xhr的5种状态.html’文件,改名为‘3_ajax_get请求.html’,其他步骤和2文件类似方法打开
页面html文件代码:
//...
<h3>该页面是测试:ajax_get请求.html</h3>
<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')
// 给按钮绑定监听
btn.onclick = () => {
// 发送ajax请求 有如下几步:
// 1.创建xhr实例对象
const xhr = new XMLHttpRequest()
// 绑定监听
xhr.onreadystatechange = ()=> {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
content.innerHTML = `<h3>${xhr.response}</h3>`
}
}
}
// 2.指定发送请求的:method、url、参数
/*
1.形如:key=value&key=value 就是query参数的urlencoded编码形式
2.形如:/xx/xxx/老刘/18 就是params参数
*/
// xhr.open('GET','http://127.0.0.1:8080/test_get?name=老刘&age=18') //携带query参数
xhr.open('GET','http://127.0.0.1:8080/test_get2/老刘/18') //携带params参数
// 3.发送请求
xhr.send()
}
</script>
</body>
</html>
服务器代码
// 1.引入express
const express = require('express')
// 2.创建app实例对象
const app = express()
// 5.解决跨域:暴露静态资源
app.use(express.static(__dirname+'/src'))
// 3.响应GET请求 -query参数
app.get('/test_get',(request,response)=>{
// 函数体
// 这里设置一句话,检查是否有人请求了
console.log('有人请求test_get了--携带的query参数是:',request.query);
response.send('hello_test_get!!!')
})
// 3.响应GET请求 -params参数
app.get('/test_get2/:name/:age',(request,response)=>{
// 函数体
// 这里设置一句话,检查是否有人请求了
console.log('有人请求test_get2了--携带的params参数是:',request.params);
response.send('hello_test_get2!!!')
})
// 4.监听
app.listen(8080,(err)=> {
if(!err) {
console.log('测试ajax请求的服务器开启成功了!测试地址如下');
console.log('http://127.0.0.1:8080/3_ajax_get请求.html');
}
})
ajax的post请求(掌握)
复制’3_ajax_get请求.html’文件,改名为‘4_ajax_post请求.html’,其他步骤和3文件类似方法打开
页面html文件代码如下:
//...
<h3>该页面是测试:ajax_post请求.html</h3>
<button id="btn">点我发送请求(原生js里的ajax的POST请求)</button>
<div id="content"></div>
<script type="text/javascript">
// 获取按钮
const btn = document.getElementById('btn')
const content = document.getElementById('content')
// 给按钮绑定监听
btn.onclick = () => {
// 发送ajax请求 有如下几步:
// 1.创建xhr实例对象
const xhr = new XMLHttpRequest()
// 绑定监听
xhr.onreadystatechange = ()=> {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
content.innerHTML = `<h3>${xhr.response}</h3>`
}
}
}
// 2.指定发送请求的:method、url、参数
// post 可以携带query params参数 和请求体body(body有两种编码形式 urlencoded 、json)
// xhr.open('POST','http://127.0.0.1:8080/test_post?name=tom&age=18') // 携带query参数
xhr.open('POST','http://127.0.0.1:8080/test_post') // 不带参数 (参数放到下方请求体发送)
// 追加响应头用于标识携带请求体参数的编码形式 --urlencoded 形式
// xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
// 追加响应头用于标识携带请求体参数的编码形式 --json 形式
xhr.setRequestHeader('Content-type','application/json')
// 3.发送请求 (post请求可以携带query、params参数,但是一般不带,而是放到请求体里面) 请求体里用urlencoded / json编码形式
const person = {
name:'老刘',
age:18
}
// xhr.send('name=老刘&age=18') //携带 urlencoded 编码形式的请求体参数
xhr.send(JSON.stringify(person)) //携带 json 编码形式的请求体参数 --使用JSON.stringify()方法将对象转为json格式
}
</script>
</body>
</html>
服务器代码:
// 1.引入express
const express = require('express')
// 2.创建app实例对象
const app = express()
// 使用中间件express.urlencoded() 解析urlencoded编码形式的请求体参数
// 简单说:如果想用express框架接收post请求所携带的请求体参数,需要借助中间件 express.urlencoded
app.use(express.urlencoded({extended:true}))
// 使用中间件解析json编码形式的请求体参数
app.use(express.json())
// 5.解决跨域:暴露静态资源
app.use(express.static(__dirname+'/src'))
// 3.响应POST请求 -请求体参数(后端需要占位符)
app.post('/test_post',(request,response)=>{
console.log('有人请求test_post了,携带的请求体参数是:',request.body);
response.send('hello_test_post!!!')
})
// 4.监听
app.listen(8080,(err)=> {
if(!err) {
console.log('测试ajax请求的服务器开启成功了!测试地址如下');
console.log('http://127.0.0.1:8080/4_ajax_post请求.html');
}
})
git相关操作
克隆仓库
例:在一个名为student_ajax文件夹右键打开Git Bush Here 使用 git clone ‘仓库地址’,拿到公司代码 (此时克隆下来的文件里面有.git文件夹,该文件夹里边配置的是克隆的远程仓库的地址)
本地环境yarn 下载依赖
git add * –将文件放到暂存区
git commit -m ‘描述干啥事情了’ –对刚才的操作进行注释
目前文件仅在本地git仓库里,还需要推送到线上仓库
git push origin master
当线上主线文件更新了之后,支线需要下载主线的最新版本,使用
git pull origin master 拉取代码
那么这样拉取后本地文件将被线上文件覆盖,所以建议单独新建个文件夹存放克隆的的仓库,每次线上有更新就拉取代码到本地该文件夹里
借助vscode去操作git
ajax解析json数据(了解)
推荐安装FeHelper(前端助手)插件到浏览器。
新建’5_ajax_解析json数据.html’
页面html文件代码如下:
// ...
<h3>该页面是:解析json数据.html</h3>
<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')
btn.onclick = ()=> {
// 1.实例化xhr对象
const xhr = new XMLHttpRequest()
// 2.绑定监听
xhr.onreadystatechange = ()=> {
if(xhr.readyState === 4) {
if(xhr.status >= 200 & xhr.status < 300) {
console.log(xhr.response);
// 将json格式解析成对象 然后使用解构赋值
// 因为不知道后端那边的数据格式,假如后端是对象,直接使用JSON.parse()就会报错 在3下方使用 xhr.responseType = 'json'解决
const {name,age,sex} = (xhr.response)
content.innerHTML = (`
<ul>
<li>姓名:${name}</li>
<li>年龄:${age}</li>
<li>性别:${sex}</li>
</ul>
`)
}
}
}
// 3.指定发送请求的:method、url (这里暂时不加参数)
xhr.open('GET','http://127.0.0.1:8080/get_person')
// 因为不知道后端那边的数据格式, responseType用于指定返回数据的格式
xhr.responseType = 'json'
// 4.发送请求
xhr.send()
}
</script>
</body>
</html>
服务器代码:
// 1.引入express
const express = require('express')
// 2.创建app实例对象
const app = express()
// 使用中间件express.urlencoded() 解析urlencoded编码形式的请求体参数
// 简单说:如果想用express框架接收post请求所携带的请求体参数,需要借助中间件 express.urlencoded
app.use(express.urlencoded({extended:true}))
// 使用中间件解析json编码形式的请求体参数
app.use(express.json())
// 5.解决跨域:暴露静态资源
app.use(express.static(__dirname+'/src'))
// 3.响应get请求
app.get('/get_person',(request,response)=>{
console.log('有人请求get_person了');
const person = {name:'老刘',age:'18',sex:'女'}
response.send(JSON.stringify(person))
//response.send('hello')
})
// 4.监听
app.listen(8080,(err)=> {
if(!err) {
console.log('测试ajax请求的服务器开启成功了!测试地址如下');
console.log('http://127.0.0.1:8080/5_ajax_解析json数据.html');
}
})
连续解构赋值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 例子 想要得到c ??
let obj = {
a:1,
b:{
c:2,
},
}
// 方法1 --标准的解构赋值得到 2
// const {c} = (obj.b)
// console.log(c); /
// 方法2 --连续解构赋值
// const {b:{c}} = obj
// console.log(c); // 得到 2
// 新需求不喜欢用c名称,改为value
// 连续解构赋值 + 重命名
const {b:{c:value}} = obj
console.log(value); // 得到 2
</script>
</body>
</html>
处理IE浏览器-get请求缓存问题(了解)
协商缓存 –一般浏览器中,当页面第一次向服务器发起请求后,服务器返回数据给页面,在控制台终端Network中可以看到请求的状态码是200。此时,当服务器中的数据更新(改变)后,页面第二次向服务器发起请求,页面数据随之变化,但是第三次点击按钮,控制台终端的状态码显示304(因为这次和上一次请求的地址都没有变化,浏览器会认为返回的信息依然和之前一样,但还是会问一问服务器,数据是否有变化,此时若服务器返回没有变化,那么浏览器会从自己缓存中读取数据,304就出现了) 所以也叫协商缓存。
但是!IE浏览器,在遇到该问题时候非常武断,直接不问服务器直接拿之前的数据给页面用。–IE的强缓存机制
解决方式:加上了时间戳参数,忽悠IE浏览器每次的请求地址不同。即使服务器接口没有参数,默认不处理请求来的参数。
// 指定发送请求的:method、url (这里暂时不加参数)
xhr.open('GET','http://127.0.0.1:8080/get_person?t='+Date.now())
请求异常与超时的处理
新建’ 7_ajax请求的异常与超时处理.html ‘文件
页面html文件代码如下:
<h3>该页面是:ajax请求的异常与超时处理.html</h3>
<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')
btn.onclick = function(){
// 1.实例化xhr对象
const xhr = new XMLHttpRequest()
// 2.绑定监听
xhr.onreadystatechange = function(){
if(xhr.readyState === 4) {
if(xhr.status >= 200 & xhr.status < 300) {
console.log(xhr.response);
const {name,age,sex} = xhr.response
content.innerHTML = (`
<ul>
<li>姓名:${name}</li>
<li>年龄:${age}</li>
<li>性别:${sex}</li>
</ul>
`)
}
}
}
// 3.指定发送请求的:method、url (这里暂时不加参数)
xhr.open('GET','http://127.0.0.1:8080/get_person_delay?t='+Date.now())
// 因为不知道后端那边的数据格式, responseType用于指定返回数据的格式
xhr.responseType = 'json'
// 网络不好的处理 --配置出错的回调
xhr.onerror = ()=>{
alert('请求出错了,可能当前网络不稳定请稍后再试');
}
//超时时间 --这个api意思是仅请求2秒,2秒后没有数据返回就取消请求
xhr.timeout = 2000
// 超时后的回调
xhr.ontimeout = () => {
alert('网速不给力,请切换网络');
}
// 4.发送请求
xhr.send()
}
</script>
</body>
</html>
服务器代码
// 3.响应get请求 --延时响应
app.get('/get_person_delay',(request,response)=>{
console.log('有人请求get_person了');
const person = {name:'海峰6',age:'18',sex:'女'}
// 3秒后返回数据
setTimeout(()=>{
response.send(JSON.stringify(person))
},3000)
})
ajax取消请求(掌握)
新建 ’ 8_ajax取消请求.html ‘
页面html文件代码如下:
// ...
<h3>该页面是:ajax取消请求.html</h3>
<button id="btn">点我发送请求(原生js里的ajax的get请求)</button>
<button id="btn2">取消请求</button>
<div id="content"></div>
<script type="text/javascript">
const btn = document.getElementById('btn')
const btn2 = document.getElementById('btn2')
const content = document.getElementById('content')
let xhr
btn.onclick = function(){
// 1.实例化xhr对象
xhr = new XMLHttpRequest()
// 2.绑定监听
xhr.onreadystatechange = function(){
if(xhr.readyState === 4) {
if(xhr.status >= 200 & xhr.status < 300) {
console.log(xhr.response);
const {name,age,sex} = xhr.response
content.innerHTML = (`
<ul>
<li>姓名:${name}</li>
<li>年龄:${age}</li>
<li>性别:${sex}</li>
</ul>
`)
}
}
}
// 3.指定发送请求的:method、url (这里暂时不加参数)
xhr.open('GET','http://127.0.0.1:8080/get_person_delay?t='+Date.now())
// 因为不知道后端那边的数据格式, responseType用于指定返回数据的格式
xhr.responseType = 'json'
// 网络不好的处理 --配置出错的回调
xhr.onerror = ()=>{
alert('请求出错了,可能当前网络不稳定请稍后再试');
}
//超时时间 --这个api意思是仅请求2秒,2秒后没有数据返回就取消请求
xhr.timeout = 2000
// 超时后的回调
xhr.ontimeout = () => {
alert('网速不给力,请切换网络');
}
// 4.发送请求
xhr.send()
// xhr.abort() //这里只要发送请求的次数多还是有概率会取消不了
}
//点击第二个按钮后触发取消请求
btn2.onclick = function() {
xhr.abort()
}
</script>
</body>
</html>
服务端代码:
// 3.响应get请求
app.get('/get_person_delay',(request,response)=>{
console.log('有人请求get_person了');
const person = {name:'海峰6',age:'18',sex:'女'}
response.send(JSON.stringify(person))
如何避免用户发送重复请求(掌握)
新建 ’ 9_避免多次重复请求.html ‘
页面html文件代码如下:
思路:点击按钮前,定义一个isLoading变量
代码执行顺序:当第一次点击按钮后,先判断isLoading变量,为假就取消。然后实例化xhr,指定发送请求的格式参数,发送请求,接着关键一点就是将isLoading变量变为真,(这样当下次点击按钮时候,isLoading变量为真就会取消下次的请求)然后判断服务器那边的状态码将isLoading变量变为假。
// ...
<h3>该页面是:避免多次重复请求.html</h3>
<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 xhr
// 声明一个变量,假如它为真代表正在发送请求中,就可以在之后取消请求
let isLoading
// 每次点击按钮 xhr将被重新实例化,即每次都被替换成新的xhr对象
btn.onclick = function(){
// 这里代表第一次点击按钮 由于isLoading为undefin 所以不会取消请求
if(isLoading) xhr.abort()
// 1.实例化xhr对象
xhr = new XMLHttpRequest()
// 4. 这是判断服务器那边的状态码 (绑定监听)
xhr.onreadystatechange = function(){
if(xhr.readyState === 4) {
if(xhr.status >= 200 & xhr.status < 300) {
isloading = false;
console.log(xhr.response);
const {name,age,sex} = xhr.response
content.innerHTML = (`
<ul>
<li>姓名:${name}</li>
<li>年龄:${age}</li>
<li>性别:${sex}</li>
</ul>
`)
}
}
}
// 2.指定发送请求的:method、url (这里暂时不加参数)
xhr.open('GET','http://127.0.0.1:8080/get_person_delay')
// 因为不知道后端那边的数据格式, responseType用于指定返回数据的格式
xhr.responseType = 'json'
// 3.发送请求
xhr.send()
isLoading = true
}
</script>
</body>
</html>
服务端代码:
// 3.响应get请求 --延时响应
app.get('/get_person_delay',(request,response)=>{
console.log('有人请求get_person了');
const person = {name:'海峰6',age:'18',sex:'女'}
// 3秒后返回数据
setTimeout(()=>{
response.send(JSON.stringify(person))
},3000)
})
jQuery封装的ajax(了解)
新建 ‘10_jquery封装的ajax.html’
打开浏览器 –下载好jquerymini.js放到文件中引入
页面html文件代码如下:
// ...
<script src="./js/jquery.min.js"></script>
</head>
<body>
<h3>该页面是:jQuery封装的ajax.html</h3>
<button id="btn1">点我发送请求(jQuery-ajax-get)</button>
<button id="btn2">点我发送请求(jQuery-ajax-post)</button>
<div id="content"></div>
<script type="text/javascript">
const btn1 = $('#btn1')
const btn2 = $('#btn2')
const content = $('#content')
btn1.click(() => {
// 使用jQyuery发送get请求 --完整版写法
$.ajax({
url: 'http://127.0.0.1:8080/test_jquery_get', //请求地址
method: 'GET', //请求方式 --不写的话默认也是get
data: { school: '麻省理工学院' }, //携带的数据
dataType: 'json', //配置响应数据格式 --将服务器拿到的json数据类型转换成对象
timeout:'2000', //指定超时的时间
// 成功的回调函数
success: (result, responseText, xhr) => { //第二个参数 responseText --代表本次响应(成功与否)的文字 第三个参数是xhr
console.log(result, responseText, xhr);
content.append(`<div>汽车名:${result.name},价格:${result.price}</div>`)
},
// 失败的回调
error: (xhr) => { //里边可以有 xhr参数
console.log('请求出错了');
}
})
// 使用jQyuery发送get请求 携带query参数 --简版写法
// 如果是params请求 /test_jquery_get/bilibili
// $.get('http://127.0.0.1:8080/test_jquery_get',{school: '麻省理工学院' },(data)=>{
// console.log(data);
// },'json')
})
btn2.click(() => {
// 使用jQyuery发送 post请求 --完整版写法
$.ajax({
url: 'http://127.0.0.1:8080/test_jquery_post', //请求地址
method: 'POST', //请求方式 --不写的话默认也是get
data: { school: '麻省理工学院' }, //携带的数据
dataType: 'json', //配置响应数据格式 --将服务器拿到的json数据类型转换成对象
timeout:'2000', //指定超时的时间
// 成功的回调函数
success: (result, responseText, xhr) => { //第二个参数 responseText --代表本次响应(成功与否)的文字 第三个参数是xhr
console.log(result, responseText, xhr);
content.append(`<div>汽车名:${result.name},价格:${result.price}</div>`)
},
// 失败的回调
error: (xhr) => { //里边可以有 xhr参数
console.log('请求出错了');
}
})
// 使用jQyuery发送post请求 携带query参数 --简版写法
// 如果是params请求 /test_jquery_post/bilibili
//$.post('http://127.0.0.1:8080/test_jquery_post',{school: '麻省理工学院' },(data)=>{
//console.log(data);
//content.append(`<div>汽车名:${data.name},价格:${data.price}</div>`)
//},'json')
})
</script>
</body>
</html>
服务端代码
// 响应GET请求 --为jQuery准备: 接收query参数 如果是params参数 --'/test_jquery_get/:school' console.log('有人请求test_jquery_get了',request.params);
app.get('/test_jquery_get',(request,response)=>{
console.log('有人请求test_jquery_get了',request.query);
const car= {name:'马自达.阿特兹',price:'25w'}
response.send(JSON.stringify(car))
})
// 响应POST请求 --为jQuery准备: 响应体:request.body
app.post('/test_jquery_post',(request,response)=>{
console.log('有人请求test_jquery_post了',request.body);
const car= {name:'马自达.阿特兹',price:'25w'}
response.send(JSON.stringify(car))
})
演示回调地狱(了解)
新建 ’ 11_演示回调地狱.html ‘
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>11_演示回调地狱.html</title>
<script src="./js/jquery.min.js"></script>
</head>
<body>
<h3>该页面是:演示回调地狱.html(看代码)</h3>
<h3>需求:点击按钮1之后发送一条请求,成功后发第二条,第二条成功后再发第三条,</h3>
<button id="btn1">点我发送请求(jQuery-ajax-get)</button>
<script type="text/javascript">
const btn1 = $('#btn1')
btn1.click(() => {
// 使用jQyuery发送get请求 携带query参数 --简版写法
$.get('http://127.0.0.1:8080/test_jquery_get',{school: '麻省理工学院' },(data)=>{
console.log(data);
$.get('http://127.0.0.1:8080/test_jquery_get',{school: '麻省理工学院' },(data)=>{
console.log(data);
$.get('http://127.0.0.1:8080/test_jquery_get',{school: '麻省理工学院' },(data)=>{
console.log(data);
},'json')
},'json')
},'json')
})
</script>
</body>
</html>
跨域问题与同源策略总结:
为什么有跨域问题?
原因是浏览器为了安全,而采用的同源策略。
浏览器中有一个ajax引擎,只要xhr请求必须走ajax引擎,ajax引擎听一个叫同源策略的话,当前后端的端口不同时,浏览器阻止页面收到请求。
什么是同源策略?
同源策略是由Netscape(网景公司)提出的一个著名安全策略,现在所有支持JavaScript的浏览器都会使用这个策略。
Web是构建同源策略协议基础之上的,浏览器只是针对同源策略的一种实现。
所谓同源是指:协议、域名(IP),端口必须要完全相同。
即:协议、域名(IP)、端口都相同,才能算是在同一个域里
备注:规则举例如下(假设已有网站地址为:http://study.cn 不写端口号时,http会使用默认的)
请求地址: 形式 结果
http://study.cn/test/a.html 协议、域名、端口均相同 成功
http://study.cn/user/a.html 协议、域名、端口均相同 成功
http://a.study.cn/user/a.html 域名不同 失败
http://study.cn:8080/tset/a.html 域名不同 失败
http://study.cn/user/a.html 协议、域名、端口均相同 成功
https://study.cn/tset/a.html 协议不同 失败
没有同源策略的危险场景:
危险场景:
有一天,你刚睡醒,收到一封邮件,说你的银行账号有风险,赶紧点进www.yinghang.com改密码。你着急的赶紧点击进去,还是熟悉的银行登陆界面,你果断输入账号密码后,还没准备看里边的余额,睡眼朦胧的你想起了平时访问的银行网站是 www.yinhang.com,不是现在访问这个。随后你收到短信,钱没了,这个钓鱼网站做了什么呢? 大概是如下思路:
新建 ’ 12_演示没有同源策略的危险场景.html ‘
<iframe id="baidu" src="https://www.baidu.com"></iframe>
<script type="text/javascript">
const iframe = window.frames['baidu']
const inputNode = iframe.document.getElementById('输入铭感信息的input的id')
console.log(inputNode.value);
</script>
非同源受到哪些限制?
Cookie不能读取;
DOM无法获得;
Ajax请求不能获取数据;
JSONP解决跨域(掌握)
JSONP是什么
JSONP (JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持get请求
同源策略限制了xhr、Cookie、DOM,但是在网页有一些标签具有跨域能力,比如:img, link, iframe, scriptJ。SONP就是利用script标签的跨域能力来发送请求的
新建文件‘13_jsonp解决跨域.html’
代码如下:
一切的前提是定义了demo(),当点击按钮后创建一个script节点并且src属性为请求的地址,将节点放入页面,最后在给window添加demo方法。
解决的原理是绕开了xhr,借助script标签发请求不收同源策略的限制。有一种前端定义函数,后端调用函数的感觉。
<body>
<!-- 这里的jquery可以发送跨域请求 --因为是在script的src下支持跨域 -->
<button id="btn">点我获取数据</button>
<script>
const btn = document.getElementById('btn')
btn.onclick = () => {
// 1.创建script节点
const scriptNode = document.createElement('script')
// 2.给节点指定src属性(请求地址)
scriptNode.src = 'http://localhost:8080/test_jsonp'
// 3.将节点放入页面
document.body.appendChild(scriptNode)
// 4.准备好一个函数
window.demo = (a) => {
console.log(a);
}
}
</script>
</body>
</html>
服务端代码:
// 响应get请求 --为jsonp跨域准备
app.get('/test_jsonp',(request,response)=>{
const person = {name:'tpm',age:18}
// 想将一个对象变成字符有两种方式:
// 1、toString() 方法 但是人类一般接受不了 --demo([object object])
// 2、JSON.stringify() 方法
response.send(`demo(${JSON.stringify(person)})`)
})
完善JSONP
优化:
1、 假如前端的函数名更改了,后端也要更改一次就很麻烦 –需要优化写法
2、前边每次点击按钮都会动态创建了一个script标签 –需要移除已经使用过的script节点
页面代码:
<body>
<!-- 这里的jquery可以发送跨域请求 --因为是在script的src下支持跨域 -->
<h3>当前页面一定不要用服务器去打开,因为要制造跨域问题,用jsonp解决问题</h3>
<button id="btn">点我获取数据</button>
<script>
const btn = document.getElementById('btn')
btn.onclick = () => {
// 1.创建script节点
const scriptNode = document.createElement('script')
// 2.给节点指定src属性(请求地址) 这里的key使用callback命名是因为前端请求,后端返回的数据是一段可以执行的js代码,这段代码触发了peiqi函数的调用
scriptNode.src = 'http://localhost:8080/test_jsonp?callback=peiqi'
// 3.将节点放入页面
document.body.appendChild(scriptNode)
// 4.准备好一个函数
window.peiqi = (a) => {
console.log(a);
}
// 5.(优化)移除已经使用过的script节点
document.body.removeChild(scriptNode)
}
</script>
</body>
</html>
服务端代码:
// 响应get请求 --为jsonp跨域准备
app.get('/test_jsonp',(request,response)=>{
const {callback} = request.query
const person = [{name:'tpm',age:18},{name:'jery',age:'16'}]
// 这样写的优势是前端的函数名随便更改,后端这里不需要改
response.send(`${callback}(${JSON.stringify(person)})`)
})
JSONP面试问题:
JSON 和 JSONP有关系吗?
有一定关系,但是他俩是两回事儿。JSON是一种存储和交互的一种格式,JSONP是后端一种解决跨域的方式。他俩的关系是因为后端返回数据的时候,必须将数据变为JSON字符串。
用JSONP去解决跨域也是用到了xhr对吗?
不对,JSONP解决跨域根本没用到xhr
JSONP解决跨域有什么缺点?
后端需要配合前端去拿到callback函数名,后端需要配合前端将数据变成JSON格式,后端需要配合前端写成函数调用的形式,简单来说前后端都挺麻烦。
jQuery封装的JSONP(了解)
用jQuery去发送一个JSONP请求:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>14_jQuery封装的JSONP.html</title>
<script src="./js/jquery.min.js"></script>
</head>
<body>
<h3>当前页面一定不要用服务器去打开,因为要制造跨域问题,用jQuery封装的JSONP解决</h3>
<button id="btn">点我获取数据</button>
<script>
const btn = $('#btn')
btn.click(()=>{
$.getJSON('http://localhost:8080/test_jsonp?callback=?',{},(data)=>{
console.log(data);
})
})
</script>
</body>
</html>
CORS (后端技术)解决跨域(掌握)
CORS 是什么?
CORS (Cross-Origin Resource Sharing), 跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 等请求。跨域资源共享标准新增了一组 HTTP 首部字段(响应头),允许服务器声明哪些源站通过浏览器有权限访问哪些资源
CORS 怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
CORS 的使用
新建 ‘ 15_测试cors解决跨域.html ’文件
代码如下:
// ...
<h3>当前页面一定不要用服务器去打开,因为要制造跨域问题,测试cors解决跨域</h3>
<button id="btn">点我获取数据</button>
<script type="text/javascript">
// 获取按钮
const btn = document.getElementById('btn')
const content = document.getElementById('content')
// 给按钮绑定监听
btn.onclick = () => {
// 发送ajax请求 有如下几步:
// 1.创建xhr实例对象
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = ()=> {
if(xhr.readyState === 4) {
if(xhr.status >= 200 & xhr.status < 300) {
console.log(xhr.response);
console.log(xhr.getAllResponseHeaders());
}
}
}
// 2.指定发送请求的:method、url
xhr.open('GET','http://127.0.0.1:8080/test_get')
// 3.发送请求
xhr.send()
}
</script>
</body>
</html>
主要是服务端的设置:
// 3.响应GET请求 -可以接收query 参数 request,response --请求、响应对象
app.get('/test_get',(request,response)=>{
console.log('有人请求test_get了--携带的query参数是:',request.query);
response.setHeader('Access-Control-Allow-Origin','http://127.0.0.1:5500') // 只允许这个 http://127.0.0.1:5500 网站进行跨域请求
response.setHeader('Access-Control-Expose-Headers','*') // 把所有的响应头都交给跨域的网站
// response.setHeader('Access-Control-Allow-Origin','*') // '*' 任何网站都可以来这个接口拿数据
// 这里设置一句话,检查是否有人请求了
response.send('hello_test_get!!!')
})
发送 put 请求
新建文件 ‘16_ajax_put请求.html’
文件代码为:
// ...
<h3>该页面是测试:ajax_put请求.html</h3>
<button id="btn">点我发送请求(原生js里的ajax的PUT请求)</button>
<div id="content"></div>
<script type="text/javascript">
// 获取按钮
const btn = document.getElementById('btn')
const content = document.getElementById('content')
// 给按钮绑定监听
btn.onclick = () => {
// 发送ajax请求 有如下几步:
// 1.创建xhr实例对象
const xhr = new XMLHttpRequest()
// 绑定监听
xhr.onreadystatechange = ()=> {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
content.innerHTML = `<h3>${xhr.response}</h3>`
}
}
}
xhr.open('PUT','http://127.0.0.1:8080/test_put')
// 3.发送请求
xhr.send()
}
</script>
</body>
</html>
服务端代码:
// 响应 put请求
app.put('/test_put',(request,response) => {
response.setHeader('Access-Control-Expose-Headers','*') // 把所有的响应头都交给跨域的网站
response.setHeader('Access-Control-Allow-Origin','*') // '*' 任何网站都可以来这个接口拿数据
response.send('hello_tset_put')
})
假如此时使用 open with live serve打开文件,将会显示跨域问题,即仅仅如上设置服务端是没有解决 put请求的跨域问题 –(预请求失败)
因为get、put属于http里的简单请求,不存在嗅探请求(也叫预请求 –在请求真正发出之前要进行一个预请求的动作 预解析 –在代码真正执行之前有人扫了一遍代码),put和delete有预请求这种嗅探请求。同时复杂请求可以检查服务器的性能,使用HTTP的OPTIONS方法,因此目前服务端没有写这个方法就会失败。所以可以在服务端的put请求之前再写一个options请求
// 预请求的方式
app.options('/test_put',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*') // '*' 任何网站都可以来这个接口拿数据
response.setHeader('Access-Control-Expose-Headers','*') // 把所有的响应头都交给跨域的网站
response.setHeader('Access-Control-Allow-Methods','*') // 预请求 这里代表哪些请求可以跨域 '*'代表任何请求都可以
response.send('我性能很好')
})
// 响应 put请求
app.put('/test_put',(request,response) => {
response.setHeader('Access-Control-Expose-Headers','*') // 把所有的响应头都交给跨域的网站
response.setHeader('Access-Control-Allow-Origin','*') // '*' 任何网站都可以来这个接口拿数据
response.send('hello_tset_put')
})
总结:掌握的需要掌握,了解的需要了解