一、网络协议
HTTP全称为HyperText Transfer Protocol,超文本传输协议,是在web上进行数据交换的基础,是一种“客户端-服务器端”协议,设计的最初是为了提供一种发布和接收HTML页面的方法。
HTTP请求与响应消息
客户端和服务端通过交换各自的消息进行交互,像浏览器发出的消息叫做请求(requests),被服务端回应的消息叫做响应(responses)。HTTP消息采用ASCII编码的多行文本构成,请求消息和响应消息具有相似的结构。
Context-type简介
Content-type是网络上传输内容的格式标准,用于定义网络文件的类型和网页的编码。
Content-type常见格式
用multipart/form-data标准传输的格式,传输数据文件为主:
- text/html:HTML格式
- text/plain:纯文本格式
- text/xml:XML格式
- image/jpeg:jpg图片格式
- image/png:png图片格式
- image/gif:gif图片格式
用application标准传输的格式,传输数据流、字符串为主:
- application/xhtml+xml:XHTML格式
- application/xml:XML数据格式
- application/atom+xml:Atom XML聚合格式
- application/json:JSON数据格式
- application/pdf:pdf格式
- application/msword:Word文档格式
- application/octet-stream:二进制流数据
JSON
JSON是JavaScript Object Notation的缩写,是一种轻量级的数据交换格式,多数用于交换字符串类型的数据。
JSON的序列化和反序列化,序列化最大的优势是跨平台的存储和数据传输,因此JSON是多数据兼容的。把在浏览器中填写的数据,通过请求通过JSON格式,发送到服务器,服务器把多条数据合并后,再用JSON格式返回浏览器响应。
FormData
FormData是HTML5新加进来的一个类,主要用于向服务器上传数据,可以模拟表单数据。相比JSON,FormData不但支持字符串传输,同时支持文件的二进制传输,因此在上传视频、图片、音频上比较有优势。
//FormData传输数据
let formData = new FormData(form);
formData.set('username','name')
// FormData传输文件
const file = document.querySelector("file_name").files[0];
let formData = new FormData();
formData.append("photo",file);
//FormData请求格式
$.ajax({
url:"",//上传地址
type:"POST",
data:formData,//传入实例化的formData对象,包含了要上传的文件
contentType:false,//在请求服务器的时候,数据有非字符串格式的内容(文件是二进制)
processData:false//formData对象不需要转换成参数字符串
})
常用服务器反馈状态码
状态码 | 英文 | 中文 |
---|---|---|
200 | OK | 客户端请求成功 |
201 | Created | 表示请求已经被成功处理 |
302 | redirect | 临时重定向 |
400 | Bad Request | 由于语法无效 |
403 | Forbidden | 拒绝授权访问 |
500 | Internal Server Error | 服务器发生不可预期的错误 |
HTTP缓存概念
缓存是一种保存资源副本并在下次请求时直接使用该副本。当Web缓存发现请求的资源已经被存储,便拦截请求,返回该资源的拷贝,而不会去原服务器重新下载。
优点:
- 缓解服务器内存消耗,减少程序执行压力,提升服务器的整体性能
- 提升服务器资源的加载速度,减少某些资源占用系统资源的时间
- 降低带宽损耗,减少网络阻塞的出现
- 提升了网站的响应速度
缓存类型:共享缓存、
强制缓存:根据Expires(请求头里的过期时间)判断,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存,并不会向服务端发起请求,展示为200状态、
协商缓存:客户端向服务端发送带有If-None-Match和If-Modified-Since的请求进行协商判断,如果资源没有变化继续使用本地缓存,记录为304状态;如果资源发生变化,服务端响应数据,记录为200状态。
缓存控制:Cache-Control头用来区分对缓存机制的支持情况,请求头和响应头都支持这个属性。
- 禁止进行缓存
Cache-Control:no-store
Cache-Control:no-cache,no-store,must-revalidate - 强制确认缓存
Cache-Control:no-cache
Pragma:no-cache - 缓存过期机制
Cache-Control:max-age=31536000
Expires:Wed,21 Oct 2015 08:00:00 GMT(0即代表过去的日期已经过期,如果在Cache-Control中设置了max-age或s-max-age指令,那么会忽略Expires) - 缓存验证确认
Cache-Control:must-revalidate
XML
XML指可扩展标记语言(EXtensible Markup Language),XML和HTML类似,HTML 指的是超文本标记语言:(HyperText Markup Language),也是标记语言
不同的是HTML中都是预定义标签,用来展示数据信息,而XML全都是自定义标签,用来传输和存储数据。
最开始AJAX使用的是XML,服务器返回的是XML格式的字符串,JS进行数据提取以及数据展示,后来XML被JSON取代,JSON更加简洁、灵活。
二、Cookie
Cookie存储于当前电脑上的文本文件中,用于在本地存储Web页面的信息的对象。
创建Cookie
function setCookie(cname,cvalue,exdays){
var d = new Date();
d.setTime(d.getTime()+(exdays*24*60*60*1000));
var expires="expires="+d.toGMTString();
document.cookie = cname+"="+cvalue+";"+expires;
}
获取Cookie
function getCookie(cname){
var name = cname+"=";
var ca = document.cookie.split(";");
for(var i=0;i<ca.length;i++){
var c= ca[i].trim();
if(c.indexOf(name)==0) return c.substring(name.length,c.length)
}
return "";
}
SessionStorage
用于临时保存同一窗口或标签页的数据。
- 存储在SessionStorage里面的数据在页面会话结束时会被清除
- 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话
- 打开多个相同的URL的Tabs页面,会创建各自的SessionStorage
- 关闭对应浏览器标签或窗口,会清除对应的SessionStorage
//保存数据到sessionStorage
sessionStorage.setItem("key","value");
//从sessionStorage获取数据
sessionStorage.getItem("key");
//删除保存的数据
sessionStorage.removeItem("key");
//从sessionStorage删除保存的所有数据
sessionStorage.clear();
LocalStorage
存储在LocalStorage的数据可以长期保留,LocalStorage中的键值对总是以字符串的形式存储。
localStorage.setItem("key","value");
localStorage.getItem("key");
localStorage.removeItem("key");
localStorage.clear()
区别
生命周期:
- Cookie的生命周期可以通过设置过期时间来控制,过期后会被自动删除。
- SessionStorage中存储的数据只在当前会话期间有效,当浏览器关闭时会被清除。
- LocalStorage中存储的数据会持久保存在客户端,即使浏览器关闭也不会丢失。即使超出了浏览器规定的大小,也不会清空数据,只会报错。
存储容量:Cookie的大小有限制,通常不能超过4KB。sessionStorage和localStorage的存储容量要大得多,一般可以达到5MB或更多。
作用域:
- Cookie和localStorage在相同的协议、主机名、端口下是共享的,可以在不同页面之间共享数据。
- sessionStorage的作用域是以窗口或标签页为单位的,它们只能在同一个窗口或标签页中共享数据。
数据传输:Cookie会随着每次HTTP请求一起发送到服务器端,这会增加额外的网络流量。而sessionStorage和localStorage中存储的数据只存在于客户端,不会被发送到服务器端。
三、ajax介绍
AJAX全称Asynchronous JavaScript And XML,就是异步的JS和XML。通过它可以在浏览器中向服务器发送异步请求,无刷新获取数据。它不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。实现AJAX的执行步骤如4.2。
1. 优点:
1.1 无需刷新页面与服务器端通信
1.2 允许根据用户事件更新部分页面内容
2. 缺点:
2.1 没有浏览历史,不能回退
2.2 存在跨域问题
2.3 SEO(搜索引擎优化)不友好,即页面上的数据是Ajax请求成功后的返回数据,在网页HTML里不存在这个信息,所以爬虫爬取不到想要的数据
四、 express 框架
Express是基于Node.js平台,快速、开放、极简的Web开发框架。可以借助这个框架,来进行一些简单的Ajax操作。
4.1 设置服务端
npm install express
基本使用:
//server.js
//1.引入express
const express = require('express');
//2.创建应用对象
const app = express();
//3.创建路由规则,request和response分别是请求报文和响应报文的封装
app.get('/',(request,response)=>{
//设置响应头,允许跨域
response.setHeader('Access-Control-Allow-Origin','*')
//响应结果
response.send('成功启动服务')
})
//4.监听端口启动服务
app.listen(8000,()=>{
console.log('服务启动,正在监听端口')
})
在当前目录下,启动终端,输入node 文件名
,即可启动http服务。在浏览器中输入127.0.0.1:8000可以访问。终止服务,在终端窗口Ctrl+C。
如果想要配置路径下访问的页面,可以这样:
//server.js
app.get('/home',(request,response)=>{
response.sendFile(_dirname + '/index.html');
//home路径下会访问相对路径下的index.html文件,作为响应页面
})
4.2 设置前台请求
get请求:
//创建XMLHttpRequest对象
const xhr = new XMLHttpRequest();
//初始化请求方式和url,与服务器建立连接
//get请求可以直接在url后面拼接参数,例:'http://127.0.0.1:8000?a=2'
xhr.open('GET','http://127.0.0.1:8000');
//xhr.open(method,url,async) async默认为true,表示是否异步
//发送请求
xhr.send();
//处理服务端返回结果的方法
//readystate 0(初始化) 1(open 调用完毕) 2(send调用完毕) 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);//响应体
console.log(xhr.responseText);//将服务器端响应作为文本字符串返回
console.log(xhr.responseXML);//将响应作为一个XMLDocument对象返回,该对象可以使用JavaScript DOM进行解析。
}
}
}
post请求:
const xhr = new XMLHttpRequest();
//设置响应体的数据类型,这样在响应时不需要手动转化json字符串
xhr.responseType= 'json'
xhr.open('POST','http://127.0.0.1:8000/server');
//设置请求头
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
xhr.send('a=100&c=200');
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response);//响应体
//如果xhr.response返回的是JSON字符串,则
console.log(JSON.parse(xhr.response))
}
}
}
同时,服务端,增加处理post请求的代码:
//server.js
const express = require('express');
const app = express();
//get为get请求、post为post请求,all为所有类型的请求,如果设置完允许所有类型请求头,还不能请求成功就改为all请求
app.get('/server',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
//如果前台传递自定义的headers,需要设置允许所有请求头
response.setHeader('Access-Control-Allow-Headers','*')
const data = {
name: 'Nick'
}
//如果想要返回json字符串,则用JSON.stringfy(data),当作send方法的参数
response.send(JSON.stringfy(data));
})
//4.监听端口启动服务
app.listen(8000,()=>{
console.log('服务启动,正在监听端口')
})
4.3 自动启动包
如果频繁进行修改server.js,可以安装nodemon这个包,如果有代码更改,可以自动重启服务端服务。
npm install -g nodemon
安装成功之后,直接nodemon server.js启动服务。
4.4 ajaxIE浏览器缓存问题
由于,IE浏览器会缓存ajax请求,响应结果不能实时更新,所以可以更改请求url,形成重新请求,来更新请求结果。
var xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/server?t=' + Date.now());
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response);//响应体
}
}
}
另一种方法区分不同浏览器中的AJAX:
var httpRequest;
if(window.XMLHttpRequest){
httpRequest = new XMLHttpRequest();
//适用于Chrome,Firefox,Safari
}else if(window.ActiveXObject){
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP")
//IE7+
}catch(e){
}
}
return httpRequest;
4.5 ajax超时以及网络异常提醒
var xhr = new XMLHttpRequest();
xhr.timeout = 2000;
//如果两秒内没有响应,就取消请求
xhr.ontimeout = function(){
alert('请求异常,请稍后重试')
}
//超时回调
xhr.onerror = function(){
alert('您的网络似乎出了一些问题!')
}
//网络异常回调
xhr.open('GET','http://127.0.0.1:8000');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response);//响应体
}
}
}
服务端代码变动:
//server.js
const express = require('express');
const app = express();
app.get('/',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
setTimeout(()=>{
response.send('延时响应')
},3000)
})
app.listen(8000,()=>{
console.log('服务启动,正在监听端口')
})
4.6 ajax取消请求以及避免重复请求
var xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000');
xhr.send();
xhr.abort();
//必须用同一个对象取消请求
如果出现服务器响应慢,用户一直没收到数据,因此一直发送重复请求的情况。这时,就可以通过新建一个标识来判断是否处在发送请求中:
var xhr = null;
if(sendflag) xhr.abort();
//如果正在发送,那么取消正在发送的请求,减轻服务器压力,重新请求
xhr = new XMLHttpRequest();
let sendflag = false;
sendflag = true;
xhr.open('GET','http://127.0.0.1:8000');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300){
console.log(xhr.response);//响应体
sendflag = false;
//请求成功后修改标识
}
}
}
五、jQuery框架的Ajax请求
服务端代码:
//server.js
const express = require('express');
const app = express();
app.all('/',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
//如果前台传递自定义的headers,需要设置允许所有请求头
response.setHeader('Access-Control-Allow-Headers','*')
var list = {result:'success'}
response.send(JSON.stringfy(list))
})
app.listen(8000,()=>{
console.log('服务启动,正在监听端口')
})
5.1 get
get方法的三个参数分别是请求地址,参数以及回调方法:
$.get('http://127.0.0.1:8000',{a:1,b:2},function(data){
console.log(data)
//data为响应结果
},'json')
//响应体自动转为json格式
5.2 post
post请求只需要,方法改为post方法,参数不变:
$.post('http://127.0.0.1:8000',{a:1,b:2},function(data){
console.log(data)
//data为响应结果
},'json')
5.3 通用请求
$.ajax({
url:'http://127.0.0.1:8000',
data:{a:1,b:2},
headers:{
c:2,
a:1
},
//自定义头
type:'GET',
dataType:'json',
//响应体结果数据类型
success:function(data){
console.log(data)
//data为响应结果
},
timeout:2000,
//超时时间
error:function(){
console.log('出错了!')
}
//失败回调
})
六、Axios的Ajax请求
6.1 安装axios包
npm install axios
以及在单页面里面直接引用:
//Using jsDelivr CDN:
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"><script>
//Using unpkg CDN:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
h5中,一些html元素提供了对CORS的支持,有一个跨域属性,它允许配置元素获取数据的CORS请求。如果说引用脚本出错,可以加上crossorigin="anonymous"
,对script元素的请求不设置凭据标志。
6.2 get请求
//配置默认url
axios.defaults.baseURL = 'http://127.0.0.1:8000'
axios.get('/',{
params:{
a:2
},//请求参数
headers:{
age:20
}//请求头
})
//基于promise的处理数据
.then(value=>{
console.log(value);
})
//.then(function(response){
// console.log(response);
//})
.catch(function(error){
console.log(error)
})
.then(function(){
//always executed
})
6.3 post请求
//配置默认url
axios.defaults.baseURL = 'http://127.0.0.1:8000'
axios.post('/',{name:'you'}//请求体,{
headers:{
age:20
}//请求头
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
6.4 ajax请求
// 发起一个post请求
axios({
method: 'post',
url: '/',
params: {
a:2
},
headers:{
age:20
},//请求头
data:{
token:"admin"
}//请求体
}).then(response=>{
console.log(response)
})
请求体与请求参数的区别,也就是params与data的区别:
get请求,请求参数在请求行中也就是url后面,同时也没有请求体,不太安全;
post请求,请求参数在请求体中,相对安全。
七、 Fetch()函数
fetch()方法用于发起获取资源的请求,它返回一个promise,这个promise会在请求响应后被resolve,并传回Response对象。
fetch('http://127.0.0.1:8000',{
method:'POST',
headers:{
name:'admin'
},
body:'name=admin'
}).then(response=>{
console.log(response)
return response.text();
//return response.json();转换成json格式
}).then(response=>{
console.log(response)
})
八、 跨域问题
ajax默认遵循同源策略,最早由netscape公司提出,是浏览器的一种安全策略。
同源:协议、域名、端口号必须完全相同。跨域即,违背同源策略。
出于安全原因,浏览器限制从脚本内发起的跨域HTTP请求。例如,XMLHttpRequest和Fetch API遵循同源策略。这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源。
常见的跨域分为以下两种:
- 完全跨域:一个顶级域名方向另一个顶级域名。
- 跨子域:相同顶级域名下的两个子级域名相互通信。
8.1 如何解决跨域
jsonp是一个非官方的跨域解决方案,支持get请求,不支持post请求。html中有一些标签,是可以跨域的,比如说script标签,用script标签来发送请求:
<script src="http://127.0.0.1:8000/jsonp"></script>
方法返回响应也是可以在控制台正常输出hello jsonp,当然返回的数据要是script标签能够解析的脚本
//server.js
const express = require('express');
const app = express();
app.all('/jsonp',(request,response)=>{
response.send('console.log("hello jsonp")')
})
app.listen(8000,()=>{
console.log('服务启动,正在监听端口')
})
jsonp怎么用:
var body = document.querySelector('body');
function changeBody(data){
body.style.border='1px solid #f00'
body.innerText = data
}
var script = document.createElement('script');
script.src = 'http://127.0.0.1:8000/jsonp';
document.body.appendChild(script);
服务端代码:
//server.js
const express = require('express');
const app = express();
app.all('/jsonp',(request,response)=>{
var data = {
result:'jsonp请求成功'
}
var str = JSON.stringfy(data);
response.send(`changeBody(${str})`);
})
app.listen(8000,()=>{
console.log('服务启动,正在监听端口')
})
8.2 jQuery发送jsonp请求
$.getJSON('http://127.0.0.1:8000/jsonp?callback=?',function(data){
console.log(data);
})
服务端代码:
//server.js
const express = require('express');
const app = express();
app.all('/jsonp',(request,response)=>{
var data = {
result:'jsonp请求成功'
}
let cb = request.query.callback;
//接收callback参数,接收到的参数是jQuery字符串
var str = JSON.stringfy(data);
response.send(`&{cb}(${str})`);
})
app.listen(8000,()=>{
console.log('服务启动,正在监听端口')
})
8.3 CORS
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get 和 post 请求。跨域资源共享标准新增了一组 HTTP 头部字段,通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
可用于发起跨域请求的头部字段,通常以access-control开头,下面是一些常用的:
//server.js
app.get('/',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
response.setHeader('Access-Control-Allow-Headers','*')
response.setHeader('Access-Control-Allow-Method','*')
response.send('CROS');
})
跨域资源共享机制的工作原理主要应用于三个场景:
- 简单请求
- 使用下列请求方法之一:GET、HEAD或POST
- 不得人为设置下列集合之外的其他首部字段:Accept、Accept-Language、Content-Language、Content-Type
- Content-Type的值仅限于下列三者之一:text/plain、multipart/form-data、application/x-www-form-urlencoded
- 预检请求(在浏览器与服务器正式请求之前,浏览器会发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的option请求称为预检请求。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。)
- 使用下列请求方法之一:PUT、DELETE、CONNECT、OPTIONS、TRACE或PATH
- 请求头中包含自定义头部字段
- 向服务器发送了application/json格式的数据
- 认证请求
- 对于跨域的XMLHttpRequest请求,浏览器不会发送身份凭证信息,如果要发送,需要设置
xmlHttpRequest.withCredentials = true;
,使得向服务器发送Cookies,服务器返回响应首部字段ACCESS-Control-Allow-Credentials:true
- 如果服务器端的响应中携带
ACCESS-Control-Allow-Credentials:true
,浏览器将不会把响应内容返回给请求的发送者。
- 对于跨域的XMLHttpRequest请求,浏览器不会发送身份凭证信息,如果要发送,需要设置