网络应用分为BS架构和CS架构这两类。BS架构指Browser+Server,浏览器+服务器的组合。CS架构指Client+Server,客户端+服务器的组合。
服务器:
从硬件的角度来说服务器是在互联网上的一台(一群)远程计算机。从软件角度来说服务器是运行在计算机上的服务端程序。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0iPfD69M-1663896962966)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220708094908775.png)]
客户端:
狭义上的的客户端指安装在客户机(手机、电脑、平板)上的应用程序。
浏览器:
通过在浏览器上运行的网页与服务端程序进行数据交互
CS:Client端展示数据、收集数据 Server端存储数据、传输数据。
BS:Broswe端展示数据、收集数据 Server端存储数据、传输数据。
广义上的客户端指用户使用的程序。
客户端与服务器要进行数据交互依赖通讯协议。在WEB应用中广泛使用的是HTTP协议。HTTP协议是应用层协议。HTTP协议底层是TCP/IP协议。
TCP/IP:协议明确了计算机之间要进行数据传输的基本条件。
HTTP协议:HTTP是一种应用层协议,它对数据传输的细节、数据的含义、数据的格式进行了规范。
HTTP中有两个重要的术语:请求和响应。
请求指客户端程序向服务端程序发送数据的过程。
响应指服务端程序向客户端程序发送数据的过程。
目前的WEB程序基本都是请求+响应这种数据交互模型。
客户端需要通过接口地址向服务器发送请求。接口地址的组成:http://IP:端口/接口名称
。
请求方式method (get/post/put/patch/delete)
请求类型contentType(form/data、json)
请求参数方式:发送给服务器的业务数据(地址栏参数、请求体参数)
**请求参数的格式:**服务要求传哪些数据必须传哪些数据。
具体采用何种方式、何种类型、参数使用什么传递方式由服务器决定,作为前端只需要按照服务器的要求发送请求就行。后端会为前端开发人员提供接口文档,文档中会详细的说明一个接口的请求方式、请求类型以及参数发送方式。
服务器会响应HTTP请求状态到客户端。该状态代表了本次请求的执行状态。
常见状态如下:
200:表示成功,服务器收到了客户端的请求并成功的响应了数据。
401:表示传输的参数格式不满足服务器的要求。
404:表示发送请求的地址不存在
500:表示服务器出现错误
服务器还会将本次请求的业务数据(JSON)响应到客户端。
当我们在进行增删改操作时,服务器只需要响应本次增删改的执行结果。
当我们在执行查询操作时,服务器除了响应本次的执行结果之外,还会将查询的数据一起响应。
客户端首先需要向服务器发送请求,服务器被动的向发送请求的客户端响应数据。
AJAX的全称 Asynchronous Java Script And XML(异步的javascript和XML)。是js中的一种异步的使用了HTTP作为通讯协议的前后端数据交互技术。
例如要通过Ajax访问和风天气接口,接口文档如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VvS0VJo5-1663896962968)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220708141807762.png)]
从文档中我们发现如下信息:
请求地址:https://devapi.qweather.com/v7/weather/now?[请求参数]
请求方式:get
请求参数:地址栏参数
参数内容:key和location,key是密钥、location城市经纬度或者城市ID
//1.创建XMLHttpRequest对象
let xhr=new XMLHttpRequest();
//2.设置请求方式和请求地址
xhr.open("GET","https://devapi.qweather.com/v7/weather/now?key=3676a20663e243ebb45d5d24ec313519&location=101040100");
//3.添加onreadystatechange事件监听ajax请求状态的变化(状态发生改变事件触发)
xhr.onreadystatechange=function(){
//ajax请求状态为4 HTTP请求状态为200表示服务器正确的响应了数据
if(xhr.readyState==4&&xhr.status==200){
let text=xhr.responseText;
let data=JSON.parse(text);
}
}
//4.发送请求
xhr.send();
$.ajax({
url:"https://devapi.qweather.com/v7/weather/now?key=3676a20663e243ebb45d5d24ec313519&location=101040100",//请求地址,默认是当前页面地址
type:"GET",//请求方式
//data:传递给服务器的数据
dataType:"JSON",//确定服务器响应的数据类型,Jquery便于转换
success:function(data){//回调函数,Juqery在服务器响应数据以后调用该回调
//data表示的是服务器响应到客户端的数据
}
});
除了Ajax函数之外,Jquery还提供了get和post的API。
Ajax的异步指请求在发出以后,程序不会就此阻塞,而是会继续向下执行,在这种情况下我们无法在ajax的请求发出以后立刻去获取数据的。异步优势是效率高,劣势是当我们多个ajax请求之间有依赖关系时(发送第二个AJAX请求需要第一个请求拿到的数据),Ajax要通过嵌套的形式来编写。
let key = "3676a20663e243ebb45d5d24ec313519";
$("#search").click(function () {
let id;
let city = $("#city").val();
//查询城市代号
let searchCity = `https://geoapi.qweather.com/v2/city/lookup?key=${key}&location=${city}`;
$.ajax({
url: searchCity,
type: "GET",
dataType: "json",
success: function (cityInfo) {
id = cityInfo.location[0].id;
//查询城市天气
let searchWeather = `https://devapi.qweather.com/v7/weather/now?key=${key}&location=${id}`;
$.ajax({
url: searchWeather,
type: "GET",
dataType: "json",
success: function (weatherInfo) {
$("#img").prop("src", `../icons/${weatherInfo.now.icon}.svg`);
$("#weather").html(weatherInfo.now.text);
$("#temp").html(weatherInfo.now.temp);
$("#sd").html(weatherInfo.now.humidity);
$("#wind").html(weatherInfo.now.windDir);
}
});
}
});
});
Ajax嵌套Ajax会造成回调地狱问题,Jquery的Ajax提供了一个可选参数,async,将其设置为false,则可以将异步Ajax设置为同步,在服务器响应数据之前,后面的代码会处于阻塞状态。
let key = "3676a20663e243ebb45d5d24ec313519";
$("#search").click(function () {
let id;
let city = $("#city").val();
//查询城市代号
let searchCity = `https://geoapi.qweather.com/v2/city/lookup?key=${key}&location=${city}`;
$.ajax({
url: searchCity,
type: "GET",
dataType: "json",
async: false,
success: function (cityInfo) {
id = cityInfo.location[0].id;
}
});
//查询城市天气
let searchWeather = `https://devapi.qweather.com/v7/weather/now?key=${key}&location=${id}`;
$.ajax({
url: searchWeather,
type: "GET",
dataType: "json",
success: function (weatherInfo) {
$("#img").prop("src", `../icons/${weatherInfo.now.icon}.svg`);
$("#weather").html(weatherInfo.now.text);
$("#temp").html(weatherInfo.now.temp);
$("#sd").html(weatherInfo.now.humidity);
$("#wind").html(weatherInfo.now.windDir);
}
});
});
在Ajax请求中,data和contentType需要根据服务器接口文档的要求灵活的传值。当接口文档中对于参数的要求是body(请求体参数)时,需要给data传值。data传值的方式由contentType来决定,默认的contentType是用于传递表单参数的。
在body中传表单参数
在body中传入表单参数要求是传入如下的数据格式:name=张三&gender=1&age=18
的字符串数据。我们可以自己将表单控件的数据取出拼成字符串,也可以使用Jquery提供serialize()函数
let form=$("#insert-form").serialize();
console.log(form);
$.ajax({
url: "http://192.168.90.79:8080/student",
type: "post",
data: form,
dataType:"json",
success:function(data){
if(data.code=="200"){
//调用select函数
select();
}
}
})
在body中传JSON参数
在body中传入JSON参数要求是传入一个JSON格式的字符串。我们可以自己定义一个对象将数据先使用对象存储起来,然后使用JSON.stringify(对象)转为JSON字符串。也可以使用jquery.serializejson.js中的serializeJSON()从一个表单中获取一个数据对象,再将对象转为JSON字符串。同时一定要注意contentType必须设置为application/json。
//使用Juqery的API将一个表单中的所有数据转为JSON对象
let json=$("#insert-form").serializeJSON();
$.ajax({
url: "http://192.168.90.79:8080/student",
type: "post",
data: JSON.stringify(json),//将JSON对象转为字符串
contentType:"application/json",
dataType:"json",
success:function(data){
if(data.code=="200"){
//调用select函数
select();
}
}
})
地址栏参数
目前后端的地址栏参数,基本都是接口地址/参数
的方式。
let id=$(this).closest("tr").children(":first").html();
$.ajax({
url:`http://192.168.90.79:8080/student/${id}`,
type:"delete",
dataType:"json",
success:function(data){
if(data.code=="200"){
select();
}
}
})
最简单的单个文件上传
<input type="file" id="file">
<input type="button" value="上传头像" id="upload-btn">
<script>
$("#upload-btn").click(function(){
//FormData是表单数据对象,通过该对象可以将表单中包含文件类的信息一起存储起来
//FormData的使用步骤:
//1.创建一个空的FormData对象
let formData=new FormData();
//2.将数据保存到FormData中,文件数据来源于表单控件
let files=$("#file")[0].files;
formData.append("file",files[0]);
//通过Ajax上传文件
$.ajax({
url:"http://192.168.90.79:8080/student/upload",
type:"post",
contentType:false,//contentType设置为false的目的是为了让Jquery将contentType值设置为multipart/form-data
processData:false,//processData是Jquery内部的参数转换开关,打开时只要参数不是字符串就会将其转为字符串,但是文件数据是二进制数据不能转为字符串,将开关关闭
data:formData,//当formData时 contentType默认就是multipart/form-data
success:function(data){
console.log(data);
}
})
});
带预览功能的带进度条的文件上传
<!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>
<script src="../js/jquery-3.6.0.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
.file-list {
width: 80%;
margin: 0 auto;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.file-list td,
.file-list th {
height: 50px;
text-align: center;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
}
.progress-box {
width: 90%;
height: 40px;
margin: 0 auto;
background-color: #EEE;
}
.progress {
width: 0%;
height: 40px;
background-color: green;
}
</style>
</head>
<body>
<input type="file" id="file">
<input type="button" value="上传" id="upload-btn">
<table class="file-list">
<tr>
<td width="10%">文件名称</td>
<td width="20%">预览图</td>
<td width="10%">文件大小</td>
<td width="10%">类型</td>
<td width="50%">进度</td>
</tr>
<!-- <tr>
<td>girl.png</td>
<td><img src="../img/id10.jpg" height="100px"></td>
<td>2.4M</td>
<td>PNG</td>
<td>
<div class="progress-box">
<div class="progress"></div>
</div>
</td>
</tr> -->
</table>
<script>
//给文件域绑定change事件
$("#file").change(function () {
//取出文件域中的第一个文件
let file = $("#file")[0].files[0];
let name = file.name;
let size = (file.size / 1024 / 1024).toFixed(2) + "M";
let type = file.type;
//使用FileReader读取出文件内容
let reader = new FileReader();
//读取文件内容需要时间,使用onload事件监听文件读取完毕
reader.onload = function () {
//先清除之前的tr
$(".file-list tr:gt(0)").remove();
//拼接tr标签
let tr = `
${name}
${reader.result}" height="100px">
${size}
${type}
`;
$(".file-list").append(tr);
}
//读取文件的内容
reader.readAsDataURL(file);
});
//给文件上传按钮绑定点击事件
$("#upload-btn").click(function () {
//FormData的使用步骤:
//1.创建一个空的FormData对象
let formData = new FormData();
//2.将数据保存到FormData中,文件数据来源于表单控件
let files = $("#file")[0].files;
formData.append("file", files[0]);
//通过Ajax上传文件
$.ajax({
url: "http://192.168.90.79:8080/student/upload",
type: "post",
contentType: false,//contentType设置为false的目的是为了让Jquery将contentType值设置为multipart/form-data
processData: false,//processData是Jquery内部的参数转换开关,打开时只要参数不是字符串就会将其转为字符串,但是文件数据是二进制数据不能转为字符串,将开关关闭
data: formData,//当formData时 contentType默认就是multipart/form-data
success: function (data) {
alert(data.message);
},
xhr:function(){
//为Jquery提供一个我们自己创建的XMLHttpRequest对象
//因为我们要为该对象绑定文件上传进度事件
let xhr=new XMLHttpRequest();
xhr.upload.onprogress=function(){
//在事件源对象中存储了已经上传的大小和总大小
let loaded=window.event.loaded;//已经上传的大小
let total=window.event.total;
let width=loaded/total*100+"%";
$(".progress").css("width",width);
}
return xhr;
}
})
});
</script>
</body>
</html>
知识点整理
如何获取文件域选中的文件:
//文件域标签对象中有属性files,保存文件域中所有选中的文件,一定是原生的DOM对象才具备该属性
document.getElementById("file").files;
doucment.querySelector("#file").files;
$("#file")[0].files
每一个文件对象中包含的属性:
let files=$("#file")[0].files;
files[下标].name;//文件名称
files[下标].size;//文件大小,单位B
files[下标].type;//文件类型
如何读取一个图片文件的内容:
//JS提供一个FileReader的对象,通过该对象可以读取图片的内容(Base64)
//1.创建FileReader对象
let reader=new FileReader();
//2.使用onload事件监听文件读取完毕
reader.onload=function(){
console.log(reader.result);//Base64内容
//img标签的src属性识别Base64数据,将内容设置到img的src属性中就可以使用img显示这张图片
}
//3.读取一个文件的内容
reader.readAsDataURL($("#file")[0].files[0]);//从文件域中取出File对象
如何监听文件上传进度
//XMLHttpRequest对象中的子对象upload可以绑定onprogress事件,它可以监听文件上传的进度
//问题:使用的是Jquery封装好的Ajax函数,无法取出其中的XMLHttpRequest对象,无法访问upload绑定事件
//解决办法:Jquery的Ajax允许我们传入一个回调函数,Jquery会调用该回调函数使用回调函数的返回值来替换原本的XMLHttpRequest对象,所以我们可以在回调函数中自己创建一个新的XMLHttpRequest对象,在该对象的upload中绑定onprogress事件,最后将XMLHttpRequest对象返回到函数调用处。
$.ajax({
......,
xhr:function(){
let a=new XMLHttpRequest();
a.upload.onprogress=function(){
//如何获取已经上传的文件大小和总大小
//在事件源对象中保存了上传的大小和总大小
window.event.loaded;//已经上传的大小
window.event.total;//总大小
}
return a;
}
})
<!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>
<script src="../js/jquery-3.6.0.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
.file-list {
width: 80%;
margin: 0 auto;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.file-list td,
.file-list th {
height: 50px;
text-align: center;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
}
.progress-box {
width: 90%;
height: 40px;
margin: 0 auto;
background-color: #EEE;
}
.progress {
width: 0%;
height: 40px;
background-color: green;
}
</style>
</head>
<body>
<input type="file" id="file" multiple>
<input type="button" value="上传" id="upload-btn">
<table class="file-list">
<tr>
<td width="10%">文件名称</td>
<td width="20%">预览图</td>
<td width="10%">文件大小</td>
<td width="10%">类型</td>
<td width="50%">进度</td>
</tr>
<!-- <tr>
<td>girl.png</td>
<td><img src="../img/id10.jpg" height="100px"></td>
<td>2.4M</td>
<td>PNG</td>
<td>
<div class="progress-box">
<div class="progress"></div>
</div>
</td>
</tr> -->
</table>
<script>
//给文件域绑定change事件
$("#file").change(function () {
//先清除之前的tr
$(".file-list tr:gt(0)").remove();
//取出文件域中的第一个文件
for (let i = 0; i < $("#file")[0].files.length; i++) {
let file = $("#file")[0].files[i];
let name = file.name;
let size = (file.size / 1024 / 1024).toFixed(2) + "M";
let type = file.type;
//使用FileReader读取出文件内容
let reader = new FileReader();
//读取文件内容需要时间,使用onload事件监听文件读取完毕
reader.onload = function () {
$(`img:eq(${i})`).prop("src", reader.result);
}
//拼接tr标签
let tr = `
${name}
${size}
${type}
`;
$(".file-list").append(tr);
//读取文件的内容
reader.readAsDataURL(file);
}
});
//给文件上传按钮绑定点击事件
$("#upload-btn").click(function () {
uploadFile();//调用文件上传函数
});
let index=0;//定义文件序号
//定义文件上传函数
function uploadFile() {
let files = $("#file")[0].files;
//FormData的使用步骤:
//1.创建一个空的FormData对象
let formData = new FormData();
//2.将数据保存到FormData中,文件数据来源于表单控件
formData.append("file", files[index]);
//通过Ajax上传文件
$.ajax({
url: "http://192.168.90.47:8080/student/upload",
type: "post",
contentType: false,//contentType设置为false的目的是为了让Jquery将contentType值设置为multipart/form-data
processData: false,//processData是Jquery内部的参数转换开关,打开时只要参数不是字符串就会将其转为字符串,但是文件数据是二进制数据不能转为字符串,将开关关闭
data: formData,//当formData时 contentType默认就是multipart/form-data
success: function (data) {
if(index<files.length-1){
index++;
uploadFile();//递
}else{
alert("上传成功");//归
}
},
xhr: function () {
//为Jquery提供一个我们自己创建的XMLHttpRequest对象
//因为我们要为该对象绑定文件上传进度事件
let a = new XMLHttpRequest();
a.upload.onprogress = function () {
//在事件源对象中存储了已经上传的大小和总大小
let loaded = window.event.loaded;//已经上传的大小
let total = window.event.total;
let width = loaded / total * 100 + "%";
$(`.progress:eq(${index})`).css("width", width);
}
return a;
}
})
}
</script>
</body>
</html>
//为Jquery提供一个我们自己创建的XMLHttpRequest对象
//因为我们要为该对象绑定文件上传进度事件
let a = new XMLHttpRequest();
a.upload.onprogress = function () {
//在事件源对象中存储了已经上传的大小和总大小
let loaded = window.event.loaded;//已经上传的大小
let total = window.event.total;
let width = loaded / total * 100 + "%";
$(`.progress:eq(${index})`).css("width", width);
}
return a;
}
})
}
```