目录
传统网站存在的问题
ajax概述 阿贾克斯
异步和同步的区别
Ajax运行原理
ajax的实现步骤
请求报文
Ajax的其他方法和Ajax配置信息
请求传参的几种格式
get/post区别
同源政策
扩展
思维导图
传统网站存在的问题
- 网速慢点情况下,页面加载时间长,用户只能等待
- 表单提交后,如果一项内容不合格,需要重新填写所有的表单内容
- 页面跳转,重新加载页面,造成资源浪费,增加用户等待时间
ajax概述 阿贾克斯
- Ajax 它本身不是一种技术
- Ajax是利用JavaScript脚本改变web应用与服务器端之间数据交互的一种方式(异步加载页面)。
- 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
- 传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。
它是浏览器提供的一套方法,可以实现页面无刷新更新数据,提高用户浏览网站应用的体验
异步和同步的区别
同步需要等待返回结果才能继续,异步不必等待
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这时浏览器仍然可以作其他事情)->处理完毕
Ajax运行原理
ajax相当于浏览器发送请求与响应的代理人,以实现在不影响用户浏览页面的情况下,局部更新页面数据,从而提高用户体验
ajax的实现步骤
1.创建ajax对象基于HttpRequest创建HTTP请求
+XML传输内容的数据格式 + HttpRequest网络请求.创建xhr实例
var xhr=new XMLHttpRequest();
2.建立连接,打开一个url地址(发送请求前的一些配置)
xhr.open(method,url,async);
-
method:请求类型,分为get和post方式;格式为字符串;
- get: (get: 一般多用于获取数据/delete:删除请求/head:获得报文首部/options:询问支持的方式)
一般是从服务器中获取数据,但是也可以传参数【取的多,给的少】
- post:(post: 主要提交表单数据和上传文件/put对数据全部进行更新/patch只对更改过的数据进行更新)
一般是给服务器发送数据,基于请求体传数据【取得少,给的多】
双方约定俗称的区别
- - GET请求传递给服务器的信息基于URL问号传参,POST是基于请求主体传数据
- - GET传输内容有大小限制【原因是URL长度有限制】超出这个长度信息会被自动截掉,这样导致传输的内容过多,最后服务器收到的信息是不完整的
- - POST相对于GET来讲更安全【相对安全,互联网面前人人都在"裸奔"】post理论上是没有限制的,但是传递的东西越多,速度越慢,可能浏览器会报传输时的错误,所以实际上我们会自己手动做限制
- - GET或产生不可控的缓存,两次及以上请求相同的api接口,并且传递的参数也一样,浏览器可能会把第一次请求的信息直接返回,而不是从服务器获取最新数据【保证每次请求的地址和参数不完全一直(URL末尾加随机数/时间戳)】
URL:请求的url地址
async:是否采用异步,默认是true
.3 注册监听 获取服务器与客户端响应的数据 监听请求的过程,在不同的阶段做不同的处理
xhr.onreadystatechange=function(){
if(xhr.readyState===4&&(xhr.status===200||xhr.status===304)){
console.log(xhr.responseText);
}
}
- xhr.response 响应主体信息「服务器返回啥格式就是啥格式」
- xhr.responseText 以字符串格式获取
- xhr.responseXML 以XML格式获取
- xhr.responseType 存储服务器返回数据的格式 空字符串{默认}、“arraybuffer”、“blob”、“document”、“json”、“text” 这些格式就是服务器支持的返回给客户端的数据格式
- xhr.status 返回的HTTP状态码
- xhr.statusText 状态码的描述
- xhr.readState//获取ajax状态码
- onreadstatechange事件 当ajax状态码发生变化时自动触发该事件
- onload:信息返回http状态码不一定是200
- onerror信息没有返回可能断网了
区分ajax状态码和http状态码
- ajax状态码:表示ajax请求的过程状态 ajax对象返回'
- http状态码:表示请求处理的结果,是服务器返回的"
服务器响的应数据格式
在真实项目中,服务器大多情况下以JSON对象为响应数据格式,当客户端拿到响应数据时,要将JSON数据和HTML字符串进行拼接,然后拼接的结果展示在页面中
- 字符串一般是json字符串
- xml格式
- 文件流格式数据(buffer二进制)
在http请求与响应的过程中,无论是请求参数是响应内容,如果是对象类型,最终都会被转为对象字符串进行传输
JSON.parse()//将json字符串转为json对象
ajax状态值(判断请求的)
存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
- 0: 请求未初始化 创造出来xhr实例就是0 (还没有调用open) UNSENT
- 1: 服务器连接已建立 执行open方法后就会由0变成1 OPENED
- 2: 请求已接收 响应头信息已经返回 HEADERS_RECEIVED
- 3: 请求处理中 响应主体信息正在处理 LOADING
-
4: 请求已完成,且响应已就绪 响应主体信息已经返回 DONE
http状态码(判断响应的)xhr.statusText 状态码的描述
- 1xx:信息响应类,表示接收到请求并且继续处理
- 2xx:处理成功响应类,表示动作被成功接收、理解和接受
- 3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理
- 4xx:客户端错误,客户请求包含语法错误或者是不能正确执行
- 5xx:服务端错误,服务器不能正确执行一个正确的请求
- 200: "OK“
- 202:服务器已经接收,但是尚为处理
- 204:服务器处理了请求,但不需要返回任何实体内容
- 206;服务器已经处理了部分GET请求
- 301:永久转移(域名迁移)
- 302:是临时转移(负载均衡)
- 304: 文件未改变,页面缓存
- 305:使用代理
- 400请求参数有误
- 401:无权限访问
- 403:服务器拒绝执行(可能会在响应主体返回)
- 404: 未找到页面,地址错误
- 405请求方式不被允许
- 408请求超时
- 500:后台的问题 未知错误
- 503 服务器超负荷
- 505http版本不支持
4 发送请求send中传递的信息,就是设置请求主体信息
基于请求主体把信息传递给服务器,但是对于传输的数据有格式的要求 推荐一款接口测试工具!POSTMAN
- - 一般格式的对象都不支持,你传的是对象,浏览器也会把其变为字符串传给服务器
- - 我们需要设置请求头中的Content-Type:让其和传递的格式相符合
shr.send()
- Get方式与post方式发送的参数不一样
- 格式:xhr.send(string);
- get方式----------
- 为get方式请求时,发送null
-
xhr.send(null);
xhr.open("get","http://www.baidu.com?name=zhangsan&age=18")
- post方式--------
- 为post方式请求时,发送具体参数xhr.send("name='lily'&age=18");
//设置请求参数格式类型(post请求必须要设置)
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded')
xhr.send("name='lily'&age=18");
请求报文
在http请求和响应过程中传递的数据块叫报文,包括要传递的数据和一些附加信息,这些信息要遵守规定好的格式
Ajax的其他方法和Ajax配置信息
Ajax的其他方法:
- xhr.getAllResponseHeaders() 获取所有响应头的信息
- xhr.getResponseHeader([key]) 获取KEY对应的响应头信息
- xhr.setRequestHeader() 设置请求头
Ajax配置信息:
设置其余的配置信息:请求头信息 & 超时 & 跨域资源共享 ...{必须在OPEN之后}
- xhr.setRequestHeader('name', 'tanghanlu'); //请求头信息的内容不能是中文或者一些特殊符号
- xhr.timeout = 60000; //设置超时时间 0就是不设置
- xhr.withCredentials = true; //在跨域资源共享中,是否允许携带资源凭证「例如:cookie」,默认false
请求传参的几种格式
发送请求「send中传递的信息,就是设置的请求主体信息」 基于请求主体传递给服务器的数据格式是有要求的「Postman接口测试工具」
默认:text/plain;charset=UTF-8
1.form-data 主要应用于文件的上传或者表单数据提交 不能使用get请求
xhr.setRequestHeader('Content-Type', 'multipart/form-data');
2. x-www-form-urlencoded格式的字符串 格式:“lx=1&name=xxx” 「常用」
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3.raw字符串格式
- 普通字符串 -> text/plain
- JSON字符串 -> application/json => JSON.stringify/parse 「常用」
- XML格式字符串 -> application/xml
4.binary进制数据文件「buffer/二进制...」
5.GraphQL(新增的,类似于查询语句)
POSTMAN从入门到精通系列(二十七):使用GraphQL_u012014531的博客-CSDN博客
get/post区别
GET传递的信息不如POST多,因为URL有长度限制「IE->2KB」,超过这个长度的信息会被自动截掉,这样导致传递内容过多,最后服务器收到的信息是不完整的!!POST理论上是没有限制的,但是传递的东西越多,速度越慢,可能导致浏览器报传输超时的错误,所以实际上我们会自己手动做限制!!
GET会产生缓存「浏览器默认产生的,不可控的缓存」:两次及以上,请求相同的API接口,并且传递的参数也一样,浏览器可能会把第一次请求的信息直接返回,而不是从服务器获取最新的信息!!xhr.open('GET', './1.json?lx=1&name=xxx&_'+Math.random())
在请求URL的末尾设置随机数,以此来清除GET缓存的副作用
POST相对于GET来讲更安全一些:GET传递的信息是基于URL末尾拼接,这个随便做一些劫持或者修改,都可以直接改了,而POST请求主体信息的劫持,没那么好做!!但是“互联网面前,人人都在裸奔”!!所以不管什么方式,只要涉及安全的信息,都需要手动加密「因为默认所有的信息传输都是明文的」!!
// 创建一个XHR对象{AJAX实例对象}
let xhr = new XMLHttpRequest;
// 打开一个URL地址{发送请求之前的配置信息}
xhr.open('GET', './data.json');
// 设置其余的配置信息:请求头信息 & 超时 & 跨域资源共享 ...{必须在OPEN之后}
xhr.setRequestHeader('name', 'tanghanlu');
xhr.timeout = 60000;
xhr.withCredentials = true;
// 监听XHR状态 & HTTP状态码
xhr.onreadystatechange = () => {
let {
status,
statusText,
readyState
} = xhr;
// 基于HTTP状态码验证是否请求成功「以2/3开始的都是成功」
if (status >= 200 && status < 400) {
if (readyState === 2) {// 响应头信息已经拿到
let serverTime = xhr.getResponseHeader('date'); //GMT 格林尼治时间
serverTime = new Date(serverTime); //把格林尼治时间变为北京时间
console.log('服务器时间:', serverTime);
}
if (readyState === 4) {
let result = xhr.responseText;
result = JSON.parse(result);
console.log('响应主体信息:', result);
}
return;
}
// 获取数据失败:提示 && 移除监听
console.log(`很遗憾,当前请求失败,请稍后再试!`, status, statusText);
xhr.onreadystatechange = null;
};
// 发送AJAX请求
// xhr.send('name=hanlu&sex=0&age=32')//post
xhr.send();//get
同源政策
ajax请求限制
ajax只能向自己的服务器发送请求,比如有一个A网站,有一个B 网站,A网站中的HTML文件只能向A网站服务器,发送Ajax请求,b网站中的HTML文件只能向b网站发送ajax请求,但是a网站不能向b网站发送ajax请求,同理b网站也不能向a网站发送ajax请求
浏览器默认存在安全访问限制:如果从当前源向另外一个源发送数据请求,默认是不允许的
什么是同源
如果两个页面的拥有相同协议,域名和端口那么两个页面就属于同一个源,其中有一个不相同就是不同源
同源政策的目的
- 同源政策是为了保护用户信息的安全,防止恶意网站窃取数据,最初的同源政策是指,A网站在客户端设置的cookie b网站是不能访问的
- 随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送ajax请求,如果请求浏览器就会报错
.如何区分是同源还是跨域?
浏览器默认存在安全访问限制:如果从当前源向另外一个源发送数据请求,默认是不允许的
WEB页面:http://127.0.0.1:5500
数据接口:https://www.jianshu.com:443
两个地址对比,如果“协议、域名、端口号”三者有一个不一致,都是跨域请求
跨域错误:Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
跨域请求在项目中的场景和意义?
@1 开发时候是跨域的,但是项目部署上线后是同源的「现在很少了」
- + 我们只需要解决开发时候的跨域问题即可
- 解决办法:修改本地的hosts文件即可「原理:构建本地DNS解析缓存」
@2 开发和部署的时候都是跨域的
- + 为了实现服务器资源的合理利用,我们一个项目都是分服务器部署的「web服务器、数据服务器、图片服务器...」
- + 需要请求第三方平台的数据
- + ...
4.跨域解决方案?
方案:CROS跨域资源共享
原理:不允许跨域是因为,当前WEB页面的“源地址 origin”向服务器发送请求的时候不被允许,所以如果想解决这个问题,只需要“服务器端”设置为允许即可Access-Control-Allow-Origin...
服务器(server.js):
设置允许源 Access-Control-Allow-Origin
+ 允许所有源,这样不安全,所以是不允许携带跨域资源凭证「例如:cookie」
+ 允许单一源 这样是可以携带资源凭证的
设置是否允许携带跨域资源凭证 WAccess-Control-Allow-Credentials
方案 JSONP
原理:==利用ajax/fetch存在域的限制(浏览器的安全策略),但是`script/link/img...`不存在域的限制
而JSONP的原理就是基于`<script src="接口请求地址">`向服务器发送请求,绕过域的限制,实现跨域数据访问。
==缺点:==JSONP只能发送GET请求,因为script请求都是get请求,不支持POST请求
==具体操作:==
- - 第一步:客户端先创建一个"全局函数" func
- - 第二步:基于script的src发送请求,同时把全局函数func传递给服务器:`src="http://api.qq.com/?callback=func"`
- - 第三步:服务器接受请求,并且获取传递进来的函数,基本callback接收
- - 第四步:准备客户端需要的数据,准备好之后,给客户端返回这样格式的内容:=="func(准备好的数据)"==
- - 第五步:客户端获取服务器返回的信息,拿到信息之后,发现是吧第一步准备的全局函数执行,把数据作为实参传递给函数,这样我们在全局函数中就可以获取服务器准备的数据。
==特点:==JSONP需要服务器端的支持:服务器端存在对应的**callback函数**
PROXY跨域代理&nginx反向代理:代理服务器
==原理:**服务器与服务器之间不存在跨域问题**==,客户端启动代理服务器(webpack/node)
- - `帮我们预览客户端项目`:基于代理服务器可以找到同项目下的页面服务环境,作用如同==open-with-liveserver==。
- - 同时实现数据请求的代理
- - 此时客户端和代理服务器是同源的
- - 服务器和服务器之间不存在跨域的限制
- ==过程:==
- 接收客户端发送的同源请求,紧接着看到真正的服务器上获取真实的数据【服务器和服务器之间不存在跨域问题】,然后把从真实服务器获取的数据返回客户端。
- - ==核心:==在于设置一个代理服务器[开发环境下我们可以基于webpack-dev-server/ndoe]设置,生产环境下我们一般是基于nginx实现代理服务器的
- - ==如何实现代理服务器:==
- - 可以基于webpack-dev-server创建【通过http-proxy】
扩展
跨域身份验证的三种方案?
方式一:==登录态校验==
- - 第一步:客户端发送POST请求做登录态校验,服务器端检验用户名密码是否准确,如果正确则返回成功
- - 第二步:客户端收到成功响应后,在**本地手动设置**cookie,存储登录成功,例如:`isLogin=true`
- - 第三步:之后再访问页面,检测本地是否有isLogin的cookie信息,有表示已经登陆过了,无需再验证
- - 缺陷: - 不准确,不安全,cookie可以随便修改
方式二:==客户端设置cookie==:会话存储
- - 第一步:客户端发送POST请求登录,
- - 第二步:服务器做账号密码验证,如果正确在响应头中设置session信息:`Set-Cookie:connect.sid`
- - 第三步:客户端收到响应头中有`Set-Cookie:connect.sid`,会在缓存中存储一份
- - 第四步:之后再访问页面,客户端会携带`connect.sid`请求校验,服务器会查找自己的session来看是否匹配成功
缺陷:
- - session中有信息则是登录,否则没登录
- - session容易丢失【过去时间、服务器重启,session信息就没有了】
- - 和cookie相关,它也容易丢失
- - 不利于服务器的分布式
- 方式三:==使用Token[常用]==
- 第一步:客户端向服务器发送登录请求,服务器进行校验:
- - 账号密码如果正确:基于JWT算法,生成一个Token信息【含有登录者、过期日期等待信息】,“服务器端不需要存储这个Token”
- - 第二步:服务器手动把Token给客户端
- - 第三步:客户端获取Token后,存储到本地:可以用`localStorage、sessionStroage、vuex/redux...`
- - 第四步:再次访问首页时,需要手动将缓存的Token发给服务器端==【基于axios的请拦截器】==
- - 第五步:服务器拿到Token后,再基于JWT反反解析,验证它的有效性
- - 优点:实时校验,要稳定以及有利于服务器分布
- - 缺点:性能略低[忽略],需要自己写代码。