AJAX
原生AJAX
AJAX简介
-
AJAX 全称为 Asynchronous JavaScript And XML,就是异步的JS和XML.
-
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据.
-
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式.
XML 简介
-
XML 可扩展标记语言.
-
XML 被设计用于传输和存储数据.
-
XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,全都是自定义标签,用来表示一些数据.
比如说我有一个学生数据:
name = "张三";age = '18';gender="男"
用 XML 表示:
<student>
<name>张三<name/>
<age>18</age>
<gender>男</gender>
</student>
现在已经被JSON取代了.用JSON表示:
{"name":"张三","age":"18","gender":"男"}
AJAX的特点
AJAX的优点
-
可以无需刷新页面与服务器端进行通信.
-
允许你根据用户事件来更新部分页面内容.
AJAX的缺点
-
没有浏览历史,不能回退.
-
存在跨域问题(同源)
-
SEO不友好
HTTP协议请求报文与响应文本结构
HTTP (hypertext transport protocol)协议[超文本传输协议].协议详细规定了浏览器和万维网服务器之间互相通信的规则。
请求报文
重点是格式与参数
请求行
- 请求方法:(get,post,move,delete等)。
- URL字段:(访问的URL信息)。/userList?ie=utf-8
- HTTP协议版本(主要有http1.0 http1.1 http2.0三种,其中http1.0属于TCP短连接类型协议,http1.1属于TCP长连接类型协议)。
请求头
由关键字和值配对组成,每行一对,关键字和值用英文冒号:分隔,请求头部的作用是客户端把请求的详细信息告诉服务端,比如
- Accept:Image/gif (媒体类型)
- Accept-Language:zh-cn(语言类型)
- Host:www.taobao.com(服务端主机名)
- Cookie:name=dd
- Content-type:application/x-form-urlencoded
- User-Agent:chorme 13
空行
空行的作用是通过发送回车符和换行符,告诉服务端请求头部结束。
请求体
主体包含了客户端要发送给服务端的信息,所以一般post类型的请求报文会有报文主体,get类型是没有的。
username=admin&password=password
响应报文
起始行
用来说明服务端响应客户端的情况,一般由协议版本号, 数字状态码, 状态情况组成。比如:
HTTP/1.1:协议类型和版本号
200:状态码
OK:状态情况(访问成功)
响应头部
- Content-type:text-html;charset=utf-8
- Accept-Encoding: gzip, deflate
- Content-Length: 112
空行,和请求报文类似.
响应报文的主体,
包含所有要返还给客户端的数据,可以是文本,也可以是图片,视频等。
不同范围状态码的含义
- 100~199:用于指定客户端执行的某些动作,表示通知信息的,如请求收到了或正在进行处理
- 200~299:表示请求成功
- 300~399:用于已经跳转的页面,表示重定向,如要完成请求还必须采取进一步的行动
- 400~499:指出客户端的错误,如请求中有语法错误或不能完成
- 500~599:指出服务端的错误,如服务器失效无法完成请求
常见状态码举例
- 404-Not found:服务器找不到客户请求的页面,可能是客户端访问了不存在的页面,
- 200-OK:访问成功
- 301-Moved Permanently:永久跳转
- 403-Fobbidden:禁止访问
- 500-Internal Server Error:内部服务器错误
- 502-Bad Geteway:坏的网关
- 503-Service Unavailable:服务当前不可用,可能是服务器维护导致
- 504-Gateway timeout:网关超时
AJAX的使用
server.js
// 1、引入express
var express = require('express');
// 2、创建应用对象
var app = express();
// 3、创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
app.get('/server', function(request, response) {
// 设置响应头 允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置响应体
response.send('hello AJAX!');
});
app.post('/server1', function(request, response) {
// 设置响应头 允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
// 设置响应体
response.send('hello POST Ajax!');
});
// 4、监听端口,启动服务
app.listen(8000,()=>{
console.log("服务已经启动,端口8000。。")
});
发送get请求
index.html
<button id="btn">发送AJAX请求</button>
<div id="result"></div>
<script>
document.getElementById('btn').addEventListener('click',function(){
// 创建对象
const xhr = new XMLHttpRequest();
// 初始化 设置请求方法和url
xhr.open('GET','http://127.0.0.1:8000/server');
// 发送
xhr.send();
// 事件绑定 处理服务器返回的结果
/**
* onreadystatechange
* 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
* readyState
* 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
* 0: 请求未初始化
* 1: 服务器连接已建立
* 2: 请求已接收
* 3: 请求处理中
* 4: 请求已完成,且响应已就绪
*/
xhr.onreadystatechange = function(){
if(xhr.readyState == '4'){
if(xhr.status >= 200 && xhr.status < 300 ){
console.log(xhr.status); // 状态码
console.log(xhr.statusText); // 状态字符串
console.log(xhr.getAllResponseHeaders()); // 所有响应头
console.log(xhr.response) // 响应体
document.getElementById('result').innerHTML = xhr.response;
}
}
}
})
发送post请求
document.getElementById('btn').addEventListener('click',function(){
const xhr = new XMLHttpRequest();
xhr.open('POST','http://127.0.0.1:8000/server1');
//设置请求头信息
xhr.setRequestHeader("Content-type","application/x-form-urlencoded");
xhr.setRequestHeader("name","dd")
// xhr.send();
// POST设置请求参数
// xhr.send('a=100&b=200');
xhr.send('a:100&b:200');
xhr.onreadystatechange = function(){
if(xhr.readyState == '4'){
if(xhr.status >= 200 && xhr.status < 300 ){
console.log(xhr.status); // 状态码
console.log(xhr.statusText); // 状态字符串
console.log(xhr.getAllResponseHeaders()); // 所有响应头
console.log(xhr.response) // 响应体
document.getElementById('result').innerHTML = xhr.response;
}
}
}
})
服务器响应json数据
document.getElementById('btn').addEventListener('click',function(){
const xhr = new XMLHttpRequest();
xhr.responseType = "json";
xhr.open('POST','http://127.0.0.1:8000/json-server');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == '4'){
if(xhr.status >= 200 && xhr.status < 300 ){
console.log(xhr.response);
// 1、手动转化
// console.log(JSON.parse(xhr.response))
// 2、自动转化 xhr.responseType = "json";
}
}
}
})
网络请求超时和网络请求错误
document.getElementById('btn').addEventListener('click',function(){
const xhr = new XMLHttpRequest();
// 超时设置
xhr.timeout = 2000;
xhr.ontimeout = function(){
alert("请求超时")
}
xhr.onerror = function(){
alert("网络异常")
}
xhr.open('GET','http://127.0.0.1:8000/delay');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == '4'){
if(xhr.status >= 200 && xhr.status < 300 ){
document.getElementById('result').innerHTML = xhr.response;
}
}
}
})
取消请求
<button id="btn">发送AJAX请求</button>
<button id="btn1">取消请求</button>
<div id="result"></div>
<script>
let xhr = null;
document.getElementById('btn').addEventListener('click',function(){
xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/delay');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == '4'){
if(xhr.status >= 200 && xhr.status < 300 ){
document.getElementById('result').innerHTML = xhr.response;
}
}
}
})
document.getElementById('btn1').addEventListener('click',function(){
console.log("取消请求");
xhr.abort();
})
</script>
Jquery中的AJAX
// get请求
$.get(url,[data],[callback],[type])
// post请求
$.post(url,[data],[callback],[type])
url:请求的URL地址
data:请求携带的参数
callback:载入成功时回调函数
type:设置返回内容格式、xml,html,script,json,text,_default
// 通用型方法
$.post({
url:请求的URL地址,
data:请求携带的参数 {a:100},
success:function(data){} 载入成功时回调函数,
dataType:'json', // 设置返回内容格式
timeout:2000, // 超时时间
error:function(data){},//失败的回调
type:请求参数 'GET',
// 头信息
headers:{
a:12
}
})
Axios
// 配置baseUrl
axios.defaults.baseUrl = "";
// get请求
axios.get(url,{
// 参数
param:{
id:'1222'
},
// 请求头信息
headers:{
name:"hh"
}
}).then((res)=>{})
//post请求
axios.post(url[, data[, config]])
axios.post(url,{
username:""
},{
param:{
id:'1222'
},
headers:{
name:"hh"
}
}).then((res)=>{})
// 通用型方法
axios({
method:"GET",
url:"",
param:{},
headers:{},
data:{}
}).then((res)=>{})
fetch
fetch(url,{
// 请求方法
method:"GET",
// 请求头
headers:{},
// 请求体
body:""
}).then(res=>{
return res.json()
}).then(res=>{
console.log(res)
})
跨域
同源策略
同源策略(Same-Origin Policy)最早由Netscape公司提出,是浏览器的一种安全策略。
同源:协议、域名、端口号 必须完全相同。
违背同源策略就是跨域。
同源策略的例子:
// 1、引入express
var express = require('express');
// 2、创建应用对象
var app = express();
// 3、创建路由规则
app.get('/home', function(request, response) {
// 响应页面
response.sendFile(__dirname+'/index.html')
});
app.get('/data',function(request, response){
response.send("请求数据")
})
// 4、监听端口,启动服务
app.listen(9000,()=>{
console.log("服务已经启动...")
});
<div>页面...</div>
<button id="btn">点击获取数据</button>
<script>
document.getElementById('btn').addEventListener('click',function(){
const xhr = new XMLHttpRequest();
// 这里因为是满足同源策略的,所以url可以简写。
xhr.open('GET','/data');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == '4'){
if(xhr.status >= 200 && xhr.status < 300 ){
console.log(xhr.response)
}
}
}
})
</script>
如何解决跨域
JSONP
1)JSONP是什么
JSONP(JSON width Padding),是一个非官方的跨域解决方法,只支持get请求。
2)JSONP怎么工作的?
在网页有一些标签天生具有跨域能力,比如img link iframe script
JSONP就是利用script标签的跨域能力来发送请求的。
app.get('/jsonp-server',function(request, response){
response.send('hello jsonp')
})
<div>页面地址</div>
<script src="http://127.0.0.1:9000/jsonp-server"></script> // 通过script标签去请求接口
报上述错误是因为通过script标签请求接口,返回的数据并非是js代码,而是字符串,所以报错。服务端修改如下:
app.get('/jsonp-server',function(request, response){
response.send("console.log('hello jsonp')")
})
界面效果如下:请求成功。
3)JSONP的使用
原生AJAX
app.get('/jsonp',function(request, response){
const data = "hello jsonp";
response.end(`handleData('${data}')`)
})
<button id="btn">发送AJAX请求</button>
<div id="result"></div>
<script>
// 处理接口获取的数据
function handleData(data){
document.getElementById('result').innerHTML = data;
}
document.getElementById('btn').addEventListener('click',function(){
// 1、创建script标签
var script = document.createElement('script')
// 2、设置script标签src属性
script.src="http://127.0.0.1:9000/jsonp";
// 3、将script标签插入到文档中
document.body.appendChild(script)
})
</script>
请求接口是一个js代码
jquery
app.get('/jquery-jsonp',function(request, response){
const data = "hello jsonp";
const cb = request.query.callback;
response.end(`${cb}('${data}')`)
})
<button id="btn">发送AJAX请求</button>
<div id="result"></div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$('#btn').on('click',function(){
$.getJSON('http://127.0.0.1:9000/jquery-jsonp?callback=?',function(res){
console.log(res);
document.getElementById('result').innerHTML = res;
})
})
</script>
CORS
1) CORS是什么?
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get和post请求。跨域资源共享标准新增了一组HTTP首部字段,允许服务器声明哪些源站通过浏览器有权访问哪些资源。
2)CORS怎么工作的?
CORS是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
3)CORS的使用
主要是服务器的设置:
app.all('/server2', function(request, response) {
// 设置响应头 允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
response.setHeader('Access-Control-Allow-Headers','*');
// 设置响应体
response.send('hello POST Ajax!');
});