语法
2024年04月17日
一、GET
function normalizeUrl(url, params) {
let queryString = Object.keys(params).reduce((prev, key) => {
return (prev += `${key}=${params[key]}&`);
}, "?");
return url + queryString.slice(0, queryString.length - 1);
}
function get(url, params) {
return new Promise((resolve, reject) => {
const normalizedUrl = normalizeUrl(url, params);
const ajax = new XMLHttpRequest();
ajax.open("GET", normalizedUrl);
ajax.addEventListener("readystatechange", function (event) {
if (ajax.readyState === 4 && [200, 304].includes(ajax.status)) {
resolve(JSON.parse(ajax.responseText));
}
});
ajax.send();
});
}
get("http://test.bolawen.com/server/sync", { a: 1, b: 2 })
.then((res) => {
console.log("res", res);
})
.catch((error) => {
console.log("error", error);
});
二、POST
2.1 text/plain
Content-Type: text/plain
数据格式
数据请求
2.2 application/json
Content-Type: application/json
JSON
是一种轻量级的数据格式,以键-值对的方式组织的数据。这个使用这个类型,需要参数本身就是json
格式的数据,参数会被直接放到请求实体里,不进行任何处理。服务端/客户端会按json
格式解析数据(约定好的情况下)。
数据格式
"{ "a": 1, "b": 2 }"
数据请求
function normalizeToJson(params){
return JSON.stringify(params)
}
function post(url, params) {
const normalizedParams = normalizeToJson(params);
return new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.open("POST", url, true);
ajax.addEventListener("readystatechange", function () {
if (ajax.readyState === 4 && [200, 304].includes(ajax.status)) {
return resolve(JSON.parse(ajax.responseText));
}
});
ajax.send(normalizedParams);
});
}
post("http://test.bolawen.com/server/sync", { a: 1, b: 2 })
.then((res) => {
console.log("res", res);
})
.catch((error) => {
console.log("error", error);
});
2.3 multipart/form-data
Content-Type: multipart/form-data
数据格式
-
普通数据
Form Data {
a: 1
b: 2
} -
文件数据
------
------
数据请求
function normalizeToFormData(params) {
const formData = new FormData();
Object.keys(params).forEach((key) => {
formData.append(key, params[key]);
});
return formData;
}
function post(url, params) {
const normalizedParams = normalizeToFormData(params);
return new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.open("POST", url, true);
ajax.addEventListener("readystatechange", function () {
if (ajax.readyState === 4 && [200, 304].includes(ajax.status)) {
return resolve(JSON.parse(ajax.responseText));
}
});
ajax.send(normalizedParams);
});
}
post("http://test.bolawen.com/server/sync", { a: 1, b: 2 })
.then((res) => {
console.log("res", res);
})
.catch((error) => {
console.log("error", error);
});
2.4 application/x-www-form-urlencoded
Content-Type: application/x-www-form-urlencoded
数据格式
a=1&b=2&c=3
数据请求
function normalizeToFormUrlencoded(params) {
const searchParams = new URLSearchParams();
Object.keys(params).forEach(key=>{
searchParams.append(key,params[key]);
});
return searchParams.toString();
}
function post(url, params) {
const normalizedParams = normalizeToFormUrlencoded(params);
return new Promise((resolve, reject) => {
const ajax = new XMLHttpRequest();
ajax.open("POST", url, true);
ajax.addEventListener("readystatechange", function () {
if (ajax.readyState === 4 && [200, 304].includes(ajax.status)) {
return resolve(JSON.parse(ajax.responseText));
}
});
ajax.send(normalizedParams);
});
}
post("http://test.bolawen.com/server/sync", { a: 1, b: 2 })
.then((res) => {
console.log("res", res);
})
.catch((error) => {
console.log("error", error);
});
三、Abort
function normalizeUrl(url, params) {
let queryString = Object.keys(params).reduce((prev, key) => {
return (prev += `${key}=${params[key]}&`);
}, "?");
return url + queryString.slice(0, queryString.length - 1);
}
function normalizeToFormUrlencoded(params) {
const searchParams = new URLSearchParams();
Object.keys(params).forEach((key) => {
searchParams.append(key, params[key]);
});
return searchParams.toString();
}
function normalizeToFormData(params) {
const formData = new FormData();
Object.keys(params).forEach((key) => {
formData.append(key, params[key]);
});
return formData;
}
function normalizeToJson(params) {
return JSON.stringify(params);
}
function normalizeBody(headers, params) {
if (!headers) {
return normalizeToJson(params);
}
const contentType =
headers["Content-Type"] ||
headers["Content-type"] ||
headers["content-type"];
if (!contentType || contentType === "application/json") {
return normalizeToJson(params);
} else if (contentType === "x-www-form-urlencoded") {
return normalizeToFormUrlencoded(params);
} else {
return normalizeToFormData(params);
}
}
function request(url, method, params, headers) {
let ajax = new XMLHttpRequest();
const baseRequest = () => {
return new Promise((resolve, reject) => {
const normalizeMethod = method.toUpperCase();
const normalizedUrl =
normalizeMethod === "GET" ? normalizeUrl(url, params) : url;
ajax.open(normalizeMethod, normalizedUrl);
ajax.addEventListener("readystatechange", function () {
if (ajax.readyState === 4 && [200, 304].includes(ajax.status)) {
return resolve(JSON.parse(ajax.responseText));
}
});
ajax.addEventListener("error", function () {
return reject("请求已出错");
});
ajax.addEventListener("abort", function () {
return reject(`请求已中断`);
});
const normalizedBody =
normalizeMethod === "GET" ? null : normalizeBody(headers, params);
ajax.send(normalizedBody);
});
};
return {
ajax,
run: baseRequest,
};
}
const { ajax, run } = request("http://test.bolawen.com/server/async", "post", {
a: 1,
b: 2,
});
run()
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
});
setTimeout(() => {
ajax.abort();
}, 3000);
四、Progress
4.1 上传
-
ajax.upload.progress
: 检索的数据量发生了变化 -
ajax.upload.load
: 传输完成,所有数据保存在response
中
let ajax;
let oldTime = 0;
let oldLoaded = 0;
const fileDom = document.getElementById("fileElm");
const processDom = document.getElementById("process");
const cancelUploadDom = document.getElementById("cancel-upload");
const restTimeTextDom = document.getElementById("rest-time-text");
const uploadSpeedTextDom = document.getElementById("upload-speed-text");
function normalizeToFormData(params) {
const formData = new FormData();
Object.keys(params).forEach((key) => {
formData.append(key, params[key]);
});
return formData;
}
function uploadLoadStart() {
oldTime = new Date().getTime();
oldLoaded = 0;
}
function transformRestTimeText(event, diffLoaded, diffTime) {
const uploadSpeed = diffLoaded / diffTime;
let restTime = (event.total - event.loaded) / uploadSpeed;
let units = "s";
if (restTime / 60 > 1) {
restTime /= 60;
units = "m";
}
if (restTime / 60 > 1) {
restTime /= 60;
units = "h";
}
restTime = restTime.toFixed(1);
restTimeTextDom.innerHTML = "剩余时间" + restTime + units;
}
function transformUploadSpeedText(diffLoaded, diffTime) {
let uploadSpeed = diffLoaded / diffTime;
let units = "b/s";
if (uploadSpeed / 1024 > 1) {
uploadSpeed = uploadSpeed / 1024;
units = "k/s";
}
if (uploadSpeed / 1024 > 1) {
uploadSpeed = uploadSpeed / 1024;
units = "M/s";
}
uploadSpeed = uploadSpeed.toFixed(1);
uploadSpeedTextDom.innerHTML = "上传速度: " + uploadSpeed + units;
}
function uploadProgress(event) {
if (event.lengthComputable) {
const percentage = Math.round((event.loaded * 100) / event.total);
processDom.value = percentage;
}
const nowTime = new Date().getTime();
const diffTime = (nowTime - oldTime) / 1000;
oldTime = nowTime;
const diffLoaded = event.loaded - oldLoaded;
oldLoaded = event.loaded;
transformUploadSpeedText(diffLoaded, diffTime);
transformRestTimeText(event, diffLoaded, diffTime);
}
function uploadLoad(event) {
process.value = 100;
restTimeTextDom.innerHTML = "已完成";
}
function uploadCancel() {
restTimeTextDom.innerHTML = "";
uploadSpeedTextDom.innerHTML = "";
}
function request(url, params) {
return new Promise((resolve, reject) => {
ajax = new XMLHttpRequest();
ajax.open("POST", url, true);
ajax.upload.addEventListener("loadstart", uploadLoadStart);
ajax.upload.addEventListener("progress", uploadProgress);
ajax.upload.addEventListener("load", uploadLoad);
ajax.addEventListener("readystatechange", function () {
if (ajax.readyState === 4 && [200, 304].includes(ajax.status)) {
return resolve(JSON.parse(ajax.responseText));
}
});
ajax.addEventListener("error", function () {
return reject("请求已出错");
});
ajax.addEventListener("abort", function () {
uploadCancel();
return reject("已取消上传");
});
ajax.send(normalizeToFormData(params));
});
}
function selectFile(e) {
const {
target: { files },
} = e;
request("http://test.bolawen.com/server/async", { file: files[0] })
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
});
}
fileDom.addEventListener("change", selectFile);
cancelUploadDom.addEventListener("click", function () {
ajax.abort();
});
4.2 下载
-
ajax.progress
-
ajax.load
补充服务
Koa Serve
const Koa = require("koa");
const KoaRouter = require("koa-router");
const { koaBody } = require("koa-body");
const app = new Koa();
const router = new KoaRouter({ prefix: "/" });
function wait(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
}
router.get("sync", async (ctx) => {
ctx.body = {
code: 200,
msg: "get 同步请求成功!",
data: ctx.request.query,
};
});
router.get("async", async (ctx) => {
await wait(8000);
ctx.body = {
code: 200,
msg: "get 异步请求成功!",
data: ctx.request.query,
};
});
router.post("sync", async (ctx) => {
ctx.body = {
code: 200,
msg: "post 同步请求成功!",
data: ctx.request.body,
};
});
router.post("async", async (ctx) => {
await wait(8000);
ctx.body = {
code: 200,
msg: "post 异步请求成功!",
data: ctx.request.body,
};
});
app.use(
koaBody({
text: true,
json: true,
multipart: true,
urlencoded: true,
})
);
app.use(router.routes());
app.listen("4000", () => {
console.log("服务启动成功!");
});