后端:服务器端
服务器端渲染 SSR(后端渲染):全部都是后端开发的
SSR 的缺点
前后端分离(客户端渲染、前端渲染)
一次 http 请求主要包括:请求和响应
请求
请求行:方法(请求方式)、URL、协议版本(目前采用的是什么版本)
请求头:客户端会默认传递过来一些信息
content-type:请求携带的数据类型(告诉服务器现在传送的数据以什么形式传过去)
<xml>
<name>liliname>
xml>
content-length:文件的大小长度
keep-alive:不立即断开,继续保持连接一会儿
acept-encoding(接收的客户端):告知服务器,客户端支持接收的文件的压缩格式
accept:我(客户端)能够接收的文件格式(一般为 json)
user-agent:客户端相关的信息
响应
第一种方式
创建 XMLHttpRequest 对象
监听状态的改变(宏任务)
xhr.open("get", "http://123.207.32.32:8000/home/multidata", false)
除了 onreadystatechange 还有其他的事件可以监听
配置请求
open方法来配置,参数如下:
method:请求的方式
URL:请求的地址
// 1.
const xhr = new XMLHttpRequest()
// 2.onload监听数据加载完成
xhr.onload = function() {
// const resJSON = JSON.parse(xhr.response)
console.log(xhr.response)
// console.log(xhr.responseText)
// console.log(xhr.responseXML)
}
// 3.告知xhr获取到的数据的类型
xhr.responseType = "json"
// xhr.responseType = "xml"
// 4.配置网络请求
// 4.1.json类型的接口
xhr.open("get", "http://xxxxx")
// 4.2.json类型的接口
// xhr.open("get", "http://xxxxx/hello_json")
// 4.3.text类型的接口
// xhr.open("get", "http://xxxxx/hello_text")
// 4.4.xml类型的接口
// xhr.open("get", "xxxxx/hello_xml")
// 5.发送网络请求
xhr.send()
<script>
// xhr四步骤:
// 1. 创建XMLHttpRequest对象
// 所有的东西都放在了 xhr 里面
const xhr = new XMLHttpRequest()
// 2. 监听状态的改变(宏任务)
xhr.onreadystatechange=function(){
if(xhr.readyState!==XMLHttpRequest.DONE)return
// 2.1将字符串转成JSON对象
// const resJSON=JSON.parse(xhr.response)
// const banners=resJSON.data.banner
log(xhr.response)
}
// 告知xhr获取到的数据的类型,默认设置为text
xhr.responseType="json"
// 3. 调用open方法进行配置
//open第三个参数boolean表示同步或者异步,默认true异步
xhr.open("get","https://www.baidu.com",false)
// 4. 调用send发送请求
xhr.send()
script>
// 1.创建对象
const xhr = new XMLHttpRequest()
// 2.监听结果
xhr.onload = function() {
console.log(xhr.status, xhr.statusText)
// 根据http的状态码判断是否请求成功
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response)
} else {
console.log(xhr.status, xhr.statusText)
}
}
xhr.onerror = function() {
console.log("onerror", xhr.status, xhr.statusText)
}
// 3.设置响应类型
xhr.responseType = "json"
// 4.配置网络请求
// xhr.open("get", "http://xxxxx/abc/cba/aaa")
xhr.open("get", "http://xxxxx/home/multidata")
// 5.发送网络请求
xhr.send()
const formEl = document.querySelector(".info")
const sendBtn = document.querySelector(".send")
sendBtn.onclick = function() {
// 创建xhr对象
const xhr = new XMLHttpRequest()
// 监听数据响应
xhr.onload = function() {
console.log(xhr.response)
}
// 配置请求
xhr.responseType = "json"
// 1.传递参数方式一: get -> query
// xhr.open("get", "http://xxxx/get?name=lili&age=18&address=广州市")
// 2.传递参数方式二: post -> urlencoded
// xhr.open("post", "http://xxxx/posturl")
// // 发送请求(请求体body)
// xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
// xhr.send("name=lili&age=18&address=广州市")
// 3.传递参数方式三: post -> formdata
// xhr.open("post", "http://xxxx/postform")
// 得将元素转成 form 对象
// // formElement对象转成FormData对象
// const formData = new FormData(formEl)
// xhr.send(formData)
// 4.传递参数方式四: post -> json
xhr.open("post", "http://xxx/postjson")
xhr.setRequestHeader("Content-type", "application/json")
xhr.send(JSON.stringify({name: "lili", age: 18, height: 1.88}))
}
function liliajax({
url,
method = "get",
data = {},
headers = {}, // token
success,
failure
} = {}) {
// 1.创建对象
const xhr = new XMLHttpRequest()
// 2.监听数据
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
success && success(xhr.response)
} else {
failure && failure({ status: xhr.status, message: xhr.statusText })
}
}
// 3.设置类型
xhr.responseType = "json"
// 4.open方法
// 一般不推荐写在 data 里面
if (method.toUpperCase() === "GET") {
// 对 data 进行遍历
const queryStrings = []
for (const key in data) {
queryStrings.push(`${key}=${data[key]}`)
}
url = url + "?" + queryStrings.join("&")
xhr.open(method, url)
xhr.send()
} else {
xhr.open(method, url)
xhr.setRequestHeader("Content-type", "application/json")
xhr.send(JSON.stringify(data))
}
return xhr
}
// 调用者
liliajax({
url: "http://xxx/get",
method: "GET",
data: {
name: "lili",
age: 18
},
success: function(res) {
console.log("res:", res)
},
failure: function(err) {
// alert(err.message)
}
})
// liliajax({
// url: "http://xxxx/postjson",
// method: "post",
// data: {
// name: "jsondata",
// age: 22
// },
// success: function(res) {
// console.log("res:", res)
// },
// failure: function(err) {
// // alert(err.message)
// }
// })
function liliajax({
url,
method = "get",
data = {},
timeout = 10000,
headers = {}, // token
} = {}) {
// 1.创建对象
const xhr = new XMLHttpRequest()
// 2.创建Promise
const promise = new Promise((resolve, reject) => {
// 2.监听数据
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response)
} else {
reject({ status: xhr.status, message: xhr.statusText })
}
}
// 3.设置类型
xhr.responseType = "json"
xhr.timeout = timeout
// 4.open方法
if (method.toUpperCase() === "GET") {
const queryStrings = []
for (const key in data) {
queryStrings.push(`${key}=${data[key]}`)
}
url = url + "?" + queryStrings.join("&")
xhr.open(method, url)
xhr.send()
} else {
xhr.open(method, url)
xhr.setRequestHeader("Content-type", "application/json")
xhr.send(JSON.stringify(data))
}
})
promise.xhr = xhr
return promise
}
const promise = liliajax({
url: "http://xxxx/get",
data: {
username: "lili",
password: "123456"
}
})
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})
<button>取消请求button>
<script>
const xhr = new XMLHttpRequest()
xhr.onload = function() {
console.log(xhr.response)
}
xhr.onabort = function() {
console.log("请求被取消掉了")
}
xhr.responseType = "json"
// 1.超市时间的设置
xhr.ontimeout = function() {
console.log("请求过期: timeout")
}
// timeout: 浏览器达到过期时间还没有获取到对应的结果时, 取消本次请求
// xhr.timeout = 3000
xhr.open("get", "http://xxxxx/timeout")
xhr.send()
// 2.手动取消结果
const cancelBtn = document.querySelector("button")
cancelBtn.onclick = function() {
xhr.abort()
}
script>
// 1.fetch发送get请求
// 1.1.未优化的代码
// fetch("xxxx").then(res => {
// // 1.获取到response
// const response = res
// // 2.获取具体的结果
// response.json().then(res => {
// console.log("res:", res)
// })
// }).catch(err => {
// console.log("err:", err)
// })
// 1.2. 优化方式一:
// fetch("xxxx").then(res => {
// // 1.获取到response
// const response = res
// // 2.获取具体的结果
// return response.json()
// }).then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err)
// })
// 1.3. 优化方式二:
// async function getData() {
// const response = await fetch("http://xxxxx")
// const res = await response.json()
// console.log("res:", res)
// }
// getData()
// 2.post请求并且有参数
async function getData() {
// const response = await fetch("http://xxxxx/postjson", {
// method: "post",
// // headers: {
// // "Content-type": "application/json"
// // },
// body: JSON.stringify({
// name: "lili",
// age: 18
// })
// })
const formData = new FormData()
formData.append("name", "lili")
formData.append("age", 18)
const response = await fetch("http://xxxx/postform", {
method: "post",
body: formData
})
// 获取response状态
console.log(response.ok, response.status, response.statusText)
const res = await response.json()
console.log("res:", res)
}
getData()
文件上传:头像上传、照片等
通过表单传给服务器
可以查看上传的进度
<input class="file" type="file">
<button class="upload">上传文件button>
<script>
// xhr/fetch
const uploadBtn = document.querySelector(".upload")
uploadBtn.onclick = function() {
// 1.创建对象
const xhr = new XMLHttpRequest()
// 2.监听结果
xhr.onload = function() {
console.log(xhr.response)
}
xhr.onprogress = function(event) {
console.log(event)
}
xhr.responseType = "json"
xhr.open("post", "http://xxxxx/upload")
// 表单
const fileEl = document.querySelector(".file")
const file = fileEl.files[0]
const formData = new FormData()
formData.append("avatar", file)
xhr.send(formData)
}
script>
<input class="file" type="file">
<button class="upload">上传文件</button>
<script>
// xhr/fetch
const uploadBtn = document.querySelector(".upload")
uploadBtn.onclick = async function() {
// 表单
const fileEl = document.querySelector(".file")
const file = fileEl.files[0]
const formData = new FormData()
formData.append("avatar", file)
// 发送fetch请求
const response = await fetch("http://xxxx/upload", {
method: "post",
body: formData
})
const res = await response.json()
console.log("res:", res)
}
</script>
import { createApp } from "vue";
import App from "./App.vue";
import axios from "axios";
createApp(App).mount("#app");
// 1. baseURL
const baseURL = "http://xxxxx:8000"
// 给axios实例配置公共的基础配置
axios.defaults.baseURL = baseURL
axios.defaults.baseURL = 10000
axios.defaults.headers = {}
// 1.1 get:
axios.get("/home/multidata").then(res => {
console.log(res.data);
})
// 1.2 get
支持多种请求方式
axios(config)
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
import { createApp } from "vue";
import App from "./App.vue";
import axios from "axios";
createApp(App).mount("#app");
//1. 发送 request请求:发送一些配置
axios
.request({
url: "http://xxxxx",
method: "get",
})
.then((res) => {
console.log(res.data);
});
// 2. 发送get请求:
// 传递参数:
// 2.1 querry参数
axios.get("http:/xxxxx/lyric?id=500665346", {}).then((res) => {
console.log(res.data);
});
// 2.2 params这个使用比较多
axios
.get("http://xxxxx/lyric", {
params: {
id: 500665346,
},
})
.then((res) => {
console.log(res.data);
});
// 3. 发送 post 请求:post请求的 url 参数是不能拼接到后面的,只能放在请求体里面
// 两种写法
axios
.post("http://xxxxx/postjson", {
username: "lili",
password: "123455",
})
.then((res) => {
console.log(res.data);
});
axios
.post("http://xxxxx/postjson", {
data: {
username: "lili",
password: "123455",
},
})
.then((res) => {
console.log(res.data);
});
// 2. axios 发送多个请求
// Promise.all
axios.all([
axios.get("/xxx/multidata"),
axios.get("/xxx/multidata2")
]).then(res => {
console.log(res.data);
})
import { createApp } from "vue";
import App from "./App.vue";
import axios from "axios";
createApp(App).mount("#app");
// axios 默认库提供给我们的实例对象
axios.get("http://xxxxx/lyric?id=500665346");
// 创建其他的实例发送网络请求
const instance1 = axios.create({
baseURL: "http://xxxx",
timeout: 6000,
headers: {},
});
instance1.get("/lyric", {
params: {
id: 500665346,
},
});
const instance2 = axios.create({
baseURL: "http://xxxxx",
timeout: 9000,
headers: {},
});
// 对实例配置拦截器
axios.interceptors.request.use(请求成功回调拦截, 请求失败回调拦截);
// 一般都不会请求失败
axios.interceptors.request.use(
(config) => {
if (config.url === "user/info") config.headers["token"] = "lili";
// 请求成功的拦截
return config;
},
(err) => {
console.log("请求失败的拦截,基本上不会发生");
}
);
// 400 404 请求失败
axios.interceptors.response.use(成功回调, 失败回调);
axios.interceptors.response.use(
(res) => {
// 这里对响应的结果进行转化
// 在得到结果的时候就不需要 res.data 了
// 响应成功的拦截
return res.data;
},
(err) => {
// 响应失败的拦截
return err;
}
);
axios
.get("http://xxxxx/lyric?id=500665346")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
import axios from "axios";
class LiliRequest {
constructor(baseURL, timeout = 10000) {
// 创建一个实例进行配置
this.instance = axios.create({
baseURL,
timeout
})
}
request(config) {
return new Promise((resolve, reject) => {
this.instance
.request(config)
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
}
get(config) {
return this.request({ ...config, method: "get" });
}
post(config) {
return this.request({ ...config, method: "post" });
}
}
const liliRequest1 = new LiliRequest("http://www.baidu.com")
const liliRequest2 = new LiliRequest("http://www.taobao.com")
export default new LiliRequest()
import liliRequest from './service/index'
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig } from "axios";
class LiliRequest {
instance: AxiosInstance;
// 1. 创建实例
// request 实例 => axios实例
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config);
}
// 2. 封装网络请求的方法
request(config: AxiosRequestConfig) {
return this.instance.request(config)
}
get() { }
}
export default LiliRequest;
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
class LiliRequest {
instance: AxiosInstance;
// 1. 创建实例
// request 实例 => axios实例
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config);
// 每个instance实例都添加拦截器
// 传入一个config对config进行修改再返回
this.instance.interceptors.request.use(
(config) => {
// loading/token
console.log("全局请求成功的拦截");
return config;
},
(err) => {
console.log("全局请求失败的拦截");
return err;
}
);
this.instance.interceptors.response.use(
(res) => {
console.log("全局响应成功的拦截");
return res;
},
(err) => {
console.log("全局响应失败的拦截");
return err;
}
);
}
// 2. 封装网络请求的方法
request(config: AxiosRequestConfig) {
return this.instance.request(config);
}
get() {}
}
export default LiliRequest;
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
import type { LILIInterceptors, LiliRequestConfig } from "./type";
class LiliRequest {
instance: AxiosInstance;
// 1. 创建实例
// request 实例 => axios实例
constructor(config: LiliRequestConfig) {
this.instance = axios.create(config);
// 每个instance实例都添加拦截器
// 传入一个config对config进行修改再返回
this.instance.interceptors.request.use(
(config) => {
// loading/token
console.log("全局请求成功的拦截");
return config;
},
(err) => {
console.log("全局请求失败的拦截");
return err;
}
);
this.instance.interceptors.response.use(
(res) => {
console.log("全局响应成功的拦截");
return res;
},
(err) => {
console.log("全局响应失败的拦截");
return err;
}
);
// 同时存在不存在覆盖
// 判断请求是否添加拦截器,针对每一个请求做精细化处理
// 针对特定的liliRequest实例添加拦截器
// if (config.interceptors) {//类型缩小
this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn);
this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn);
// }
}
// 2. 封装网络请求的方法
request(config: AxiosRequestConfig) {
return this.instance.request(config);
}
get() {}
}
export default LiliRequest;
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
import type { LILIInterceptors, LiliRequestConfig } from "./type";
class LiliRequest {
instance: AxiosInstance;
// 1. 创建实例
// request 实例 => axios实例
constructor(config: LiliRequestConfig) {
this.instance = axios.create(config);
// 每个instance实例都添加拦截器
// 传入一个config对config进行修改再返回
this.instance.interceptors.request.use(
(config) => {
// loading/token
console.log("全局请求成功的拦截");
return config;
},
(err) => {
console.log("全局请求失败的拦截");
return err;
}
);
this.instance.interceptors.response.use(
(res) => {
console.log("全局响应成功的拦截");
return res;
},
(err) => {
console.log("全局响应失败的拦截");
return err;
}
);
// 同时存在不存在覆盖
// 判断请求是否添加拦截器,针对每一个请求做精细化处理
// 针对特定的liliRequest实例添加拦截器
// if (config.interceptors) {//类型缩小
this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn);
this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn);
// }
}
// 2. 封装网络请求的方法
request(config: LiliRequestConfig) {
// 拦截器的本质是一些钩子函数,对其进行回调
if (config.interceptors?.requestSuccessFn) {
config = config.interceptors.requestSuccessFn(config);
}
return new Promise((resolve, reject) => {
this.instance
.request(config)
.then((res) => {
if (config.interceptors?.responseSuccessFn) {
res = config.interceptors.responseSuccessFn(res);
}
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
get() {}
}
export default LiliRequest;
import liliRequest from "..";
interface IHmoeData{
data: any,
returnCode: string,
success:boolean
}
liliRequest.request<IHmoeData>({
url:"/user/name"
}).then(res => {
console.log(res);
})
// 2. 封装网络请求的方法
request<T=any>(config: LiliRequestConfig) {
// 拦截器的本质是一些钩子函数,对其进行回调
if (config.interceptors?.requestSuccessFn) {
config = config.interceptors.requestSuccessFn(config);
}
return new Promise<T>((resolve, reject) => {
this.instance
.request<any,T>(config)
.then((res) => {
if (config.interceptors?.responseSuccessFn) {
// res = config.interceptors.responseSuccessFn(res);
}
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 拦截器:蒙版 loading/token/修改配置
import type { LILIInterceptors, LiliRequestConfig } from "./type";
class LiliRequest {
instance: AxiosInstance;
// 1. 创建实例
// request 实例 => axios实例
constructor(config: LiliRequestConfig) {
this.instance = axios.create(config);
// 每个instance实例都添加拦截器
// 传入一个config对config进行修改再返回
this.instance.interceptors.request.use(
(config) => {
// loading/token
console.log("全局请求成功的拦截");
return config;
},
(err) => {
console.log("全局请求失败的拦截");
return err;
}
);
this.instance.interceptors.response.use(
(res) => {
console.log("全局响应成功的拦截");
return res.data;
},
(err) => {
console.log("全局响应失败的拦截");
return err;
}
);
// 同时存在不存在覆盖
// 判断请求是否添加拦截器,针对每一个请求做精细化处理
// 针对特定的liliRequest实例添加拦截器
// if (config.interceptors) {//类型缩小
this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn);
this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn);
// }
}
// 2. 封装网络请求的方法
request<T=any>(config: LiliRequestConfig<T>) {
// 拦截器的本质是一些钩子函数,对其进行回调
if (config.interceptors?.requestSuccessFn) {
config = config.interceptors.requestSuccessFn(config);
}
return new Promise<T>((resolve, reject) => {
this.instance
.request<any,T>(config)
.then((res) => {
if (config.interceptors?.responseSuccessFn) {
// res = config.interceptors.responseSuccessFn(res);
}
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
get() {}
}
export default LiliRequest;
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
// 针对AxiosRequestConfig配置进行扩展
export interface LILIInterceptors<T=AxiosResponse> {
requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig;
requestFailureFn?: (err: any) => any;
responseSuccessFn?: (res: T) => T;
responseFailureFn?: (err: any) => any;
}
export interface LiliRequestConfig<T=AxiosResponse> extends AxiosRequestConfig {
interceptors?: LILIInterceptors<T>;
}
get<T = any>(config: LiliRequestConfig<T>) {
return this.request({...config,method:"GET"})
}
post<T = any>(config: LiliRequestConfig<T>) {
return this.request({...config,method:"POST"})
}
delete<T = any>(config: LiliRequestConfig<T>) {
return this.request({...config,method:"DELETE"})
}
patch<T = any>(config: LiliRequestConfig<T>) {
return this.request({...config,method:"PATCH"})
}