目录1.Http 简介HTTP/0.9 ( 1991 )HTTP/1.0 (1996 )HTTP/1.1(1997)常用状态码header请求头header响应头Content-Ty
HTTP ( HyperText Transfer Protocol)
超文本传输协议,是万维网(World Wide WEB)
的基础协议GET
请求HTTP
头,只能传输 html 文件200
、404
等HTTP
头,多了传递信息的手段,更加灵活和方便扩展content-type
属性,具备了传输除纯文本 HTML
文件以外其他类型文档的能力tcp
连接。1.0
每次请求都需要重新建立连接。HTTP1.x请求报文
HTTP1.x响应报文
名字 | 说明 | 示例 |
---|---|---|
Accept | 告知(服务器)客户端可以处理的内容类型 | text/html, application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
Aaccept-Encoding | 客户端能够理解的内容编码方式 | gzip, deflate |
Accept-Language | 客户端可以理解的语言 | zh-CN,zh;q=0.9,en;q=0.8 |
Cache-Control | 表示浏览器的缓存方式 | Cache-Control: max-age = xxx |
cookie | cookie信息 | |
Connection | 是否是长连接 | keep-live |
Content-Type | 实际发送的数据类型 | content-type:application/x-www-form |
Host | 要发送到的服务器主机名和端口号 | www.baidu.com |
User-Agent | 用户代理。包含应用类型、操作系统、软件开发商以及版本号等 | |
Referer | 当前请求的来源页面的地址 |
名字 | 说明 | 示例 |
---|---|---|
Date | 服务器的响应的日期和时间 | |
Connection | 是否会关闭网络连接 | Connection: keep-alive |
Keep-Alive | 空闲连接需要保持打开状态Keep-Alive: timeout=5, max=10的最小时长和最大请求数( Connection设置为“keep-alive”才有意义) | Keep-Alive: timeout=5, max=10空闲5秒,最多接收10次请求就断开。 |
Content-Encoding | 内容编码方式 | Content-Encoding: gzip |
Content-Length | 报文中实体主体的字节大小 | content-Length: 1963 |
Content-Type | 内容的内容类型 | Content-Type: text/html; charset=utf-8 |
Server | 服务器所用到的软件相关信息 | Server: openresty 基于Nginx的可伸缩的Web平台 |
Set-Cookie | 向客户端发送cookie | Set-Cookie: imooc_isnew=2; expires=Thu, 02-Mar-202312:3242 GMT; Max-Age=31536000; path=/; domain=.baidu.com |
<body>
<button type="button" id="btnSend">发送请求</button>
<div>
<div>结果:</div>
<div id="result"></div>
</div>
<script>
btnSend.onclick = fetchByUrlencoded;
function fetchByUrlencoded() {
// 对中文还能自行编码
// const params = new URLSearchParams({
// name: 'yunmu',
// age: 18
// });
fetch("/urlencoded", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: "name=yunmu&age=18",
// body: params.toString()
})
.then((res) => res.json())
.then((res) => {
console.log("收到结果:", res);
result.innerHTML = JSON.stringify(res);
});
}
</script>
</body>
<body>
<div>结果:</div>
<div id="result"></div>
<div>表单提交</div>
<form action="/multipart" method="post" enctype="multipart/form-data">
<input type="text" name="name" value="tom" />
<input type="text" name="age" value="18" />
<button type="submit">提交表单</button>
</form>
<hr />
<div>代码提交:</div>
<button type="button" id="btnSend">发送请求</button>
<script>
btnSend.onclick = fetchByMultipart;
function fetchByMultipart() {
const formData = new FormData();
formData.append("name", "yunmu");
formData.append("age", 18);
fetch("/multipart", {
method: "POST",
// 不要设置 content-type
// headers: {
// "Content-Type": "multipart/form-data",
// },
body: formData,
})
.then((res) => res.json())
.then((res) => {
console.log("收到结果:", res);
result.innerHTML = JSON.stringify(res);
});
}
</script>
</body>
<body>
<button type="button" id="btnSend">发送请求</button>
<div>
<div>结果:</div>
<div id="result"></div>
</div>
<script>
btnSend.onclick = fetchByJSON;
function fetchByJSON() {
fetch("/json", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "yunmu", age: 18 }),
})
.then((res) => {
console.log("返回的content-type:", res.headers.get("Content-Type"));
return res;
})
.then((res) => res.json())
.then((res) => {
console.log("收到结果:", res);
result.innerHTML = JSON.stringify(res);
});
}
</script>
</body>
服务端代码:
const express = require("express");
const path = require("path");
const multer = require("multer");
const server = express();
server.use(
express.urlencoded({
extended: true,
})
);
server.use(express.json());
server.use(express.static(path.join(__dirname, "./static")));
server.use("/urlencoded", function (req, res) {
console.log("收到请求(urlencoded)");
console.log("body:", req.body);
res.json({
code: 10000,
data: req.body,
});
});
server.use("/multipart", multer().none(), function (req, res) {
console.log("收到请求(multipart)");
console.log("body:", req.body);
res.json({
code: 10000,
data: req.body,
});
});
server.use("/json", multer().none(), function (req, res) {
console.log("收到请求(json)");
console.log("body:", req.body);
res.json({
code: 10000,
data: req.body,
});
});
server.listen(3000, function () {
console.log("listening at port 3000");
});
HTTPS (Hypertext Transfer Protocol Secure)
:超文本传输安全协议,在HTTP的基础上加了一个 Secure
安全HTTPS
是HTTP
协议的一种扩展,使用传输层安全性(TLS)
或安全套接字层(SSL)
对通信协议进行加密HTTP + SSL(TLS) = HTTPS
Asynchronous javascript And XML
(异步JavaScript和XML )HTML
或 XHTML
、CSS
、JavaScript
、DOM
、XML
、XSLT
,以及最重要的XMLHttpRequest
基本使用:
<body>
<div>测试ajax 界面</div>
<button id="ajaxBtn">AjAX局部刷新</button>
<div class="ajax-change" id="responseDiv">change区域</div>
<script>
function test() {
//1. 创建实例对象
const xhrObj = new XMLHttpRequest();
//注册readystatechange回调监听
xhrObj.onreadystatechange = function () {
//readyState==4 && status=200 代表请求成功
if (xhrObj.readyState == 4 && xhrObj.status == 200) {
//局部刷新文本
document.getElementById("responseDiv").innerHTML = xhrObj.responseText;
}
};
//请求错误回调
xhrObj.onerror = function () {
console.log("-------onerror-------:");
};
//请求成功完成回调
xhrObj.onload = function () {
console.log("-------onload-------:", xhrObj.responseText);
};
//请求开始回调
xhrObj.onloadstart = function () {
console.log("-------onloadstart-------");
};
//请求完成回调,不论请求成功与否
xhrObj.onloadend = function () {
console.log("-------onloadend-------");
};
//设置请求地址,true 异步请求,false:同步请求,
xhrObj.open("post", "http://127.0.0.1:3000/xhr", true);
//设置请求携带header
xhrObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//发送请求数据
xhrObj.send("xhr=1");
}
document.getElementById("ajaxBtn").addEventListener("click", function () {
test();
});
</script>
</body>
服务端代码:
import http from "http";
import bodyParser from "body-parser";
import express from "express";
import createError from "http-errors";
// const multiparty = require('multiparty');
const port = 3000;
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
const server = http.createServer(app);
//设置跨域访问
app.use(function (req, res, next) {
//设置允许跨域的域名,*代表允许任意域名跨域
//"*"
res.header("Access-Control-Allow-Origin", req.headers.origin);
//允许携带cookie
res.header("Access-Control-Allow-Credentials", "true");
//允许的header类型
res.header("Access-Control-Allow-Headers", [
"X-PINGoTHER",
"content-type",
"Origin",
"X-Requested-With",
]);
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
res.header("Access-Control-Max-Age", `${20}`);
if (req.method.toLowerCase() == "options") res.send(200);
//让options尝试请求快速结束
else next();
});
app.post("/xhr", async (_req, _res) => {
console.log("xhr: 收到请求");
await sleep(2 * 1000);
_res.json({
code: 10000,
});
});
function sleep(time: number) {
return new Promise((resolve) => setTimeout(resolve, time));
}
app.get("/fetch", async (_req, res) => {
console.log("fetch:收到请求", _req.url);
await sleep(10 * 1000);
return res.json({
code: 10000,
});
});
app.get("/test1", (_req, res) => {
res.send("test1");
});
app.get("/test2", (_req, res) => {
res.send("test2");
});
app.get("/timeout", async (_req, res) => {
await sleep(12 * 1000);
res.send("test2");
});
app.get("/test4", async (_req, res) => {
console.log("收到请求=test4=", _req.url);
// res.send('hello')
await sleep(30000);
return res.json({
REV: true,
DATA: {
msg: "成功",
},
});
});
server.listen(port, () => {
console.log("监听端口:", port);
});
// catch 404 and forward to error handler
app.use((_req: express.Request, _res: express.Response, next: express.NextFunction) => {
const error = createError(404);
next(error);
});
process.on("unhandledRejection", (reason: {} | null | undefined, p: Promise<any>) => {
console.error("自定义错误 Unhandled Rejection at:", p, "reason:", reason);
// application specific logging, throwing an error, or other logic here
});
Promise
语法,解决了回调地狱问题Request
, Response
等通用对象301
,302
等跳转(Stream)
,方便处理大文件基本使用:
<script>
// get
fetch("http://127.0.0.1:3000/test1")
.then((response) => response.text())
.then((text) => console.log("获取到的数据对象:", text))
.catch((err) => console.log("Request Failed", err));
//post
fetch("http://127.0.0.1:3000/report", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;",
},
body: "report=2",
mode: "cors", //设置跨域
})
.then((response) => response.json())
.then((json) => console.log("post 获取到的数据对象:", json))
.catch((err) => console.log("Request Failed", err));
</script>
拦截3xx重定向
<body>
<div>
<button id="btnXhr">XHR</button>
<button id="btnFetch">Fetch</button>
</div>
<script>
btnXhr.onclick = xhr30x;
btnFetch.onclick = fetch30x;
function fetch30x() {
fetch("http://www.baidu.com", { redirect: "error" }).catch((err) =>
console.log("err:", err)
);
}
function xhr30x() {
const xhrObj = new XMLHttpRequest();
xhrObj.onreadystatechange = function () {
console.log("xhrObj.status==", xhrObj.status);
};
xhrObj.open("get", "http://www.baidu.com", true);
//设置请求携带header
xhrObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//发送请求数据
xhrObj.send("xhr=1");
xhrObj.onerror = function () {
console.log("-------onerror-------:");
};
}
</script>
</body>
API
实现(AbortController
和AbortSignal
)XHR
的onProgress
事件Response.body
给我们返回了一个ReadableStream
对象Promise
的reject
回调AbortController
对象的abort()
<body>
<div>测试fetch 界面</div>
<button id="btnSend">发送请求</button>
<button id="btnCancel">取消请求</button>
<script>
const controller = new AbortController();
const signal = controller.signal;
btnSend.onclick = function sendFetch(test) {
fetch("http://127.0.0.1:3000/fetch", { signal })
.then((response) => {
return response.text();
})
.then((text) => {
console.log(text);
});
};
btnCancel.onclick = function () {
console.log("取消请求");
controller.abort();
};
</script>
</body>
const controller = new AbortController();
const signal = controller.signal;
axios.get("/foo", {
signal,
}).then(() => {});
// 取消请求
controller.abort();
<body>
<div>测试ajax 界面</div>
<button id="ajaxBtn">AjAX局部刷新</button>
<script>
function test() {
// 创建实例对象
const xhrObj = new XMLHttpRequest();
xhrObj.responseType = "blob";
//onprogress
xhrObj.onprogress = function (event) {
console.log(
"total:",
event.total,
"progress:",
event.loaded,
"%:",
(event.loaded / event.total) * 100 + "%"
);
if (event.lengthComputable) {
console.log("获取完毕");
}
};
xhrObj.open("get", "./test.mp4", true);
//发送请求数据
xhrObj.send();
//请求成功完成后下载
// xhrObj.onload = function (oEvent) {
// console.log(oEvent, "oEvent===");
// console.log(xhrObj.status, "status===");
// console.log(xhrObj.response, "response===");
// if (xhrObj.readyState === 4 && xhrObj.status === 200) {
// const blob = new Blob([xhrObj.response]);
// const video = URL.createObjectURL(blob);
// const link = document.createElement("a");
// link.href = video;
// link.download = "test.mp4";
// link.click();
// }
// };
}
document.getElementById("ajaxBtn").addEventListener("click", function () {
test();
});
</script>
</body>
<body>
<script>
let progress = 0;
let contentLength = 0;
fetch("./test.mp4")
.then((response) => {
// 通过响应头获取文件大小
contentLength = response.headers.get("Content-Length");
const reader = response.body.getReader();
return reader.read().then(function processResult(result) {
if (result.done) {
console.log("请求完毕");
return;
}
progress += result.value.byteLength;
console.log(
"total:",
contentLength,
"progress:",
progress,
"%:",
(progress / contentLength) * 100 + "%"
);
return reader.read().then(processResult);
});
})
.catch((err) => console.log("Request Failed", err));
</script>
</body>
<body>
<div>测试ajax 界面</div>
<button id="ajaxBtn">发起超时请求</button>
<div class="ajax-change" id="responseDiv">change区域</div>
<script>
function test() {
//1. 创建实例对象
const xhrObj = new XMLHttpRequest();
//请求错误回调
xhrObj.onerror = function () {
console.log("-------onerror-------:");
};
//请求完成回调,不论请求成功与否
xhrObj.onloadend = function () {
console.log("-------onloadend-------");
};
//超时监听
xhrObj.ontimeout = function () {
console.error("The request timed out.");
document.getElementById("responseDiv").innerHTML = "The request timed out";
};
//设置网络超时时间
xhrObj.timeout = 5 * 1000;
xhrObj.open("GET", "http://127.0.0.1:3000/timeout", true);
//发送请求数据
xhrObj.send();
}
document.getElementById("ajaxBtn").addEventListener("click", function () {
test();
});
</script>
</body>
<body>
<div>fetch 不支持超时</div>
<button id="ajaxBtn">发起超时请求</button>
<div class="ajax-change" id="responseDiv">change区域</div>
<script>
const oldFetch = fetch;
window.fetch = function (input, opts) {
return new Promise(function (resolve, reject) {
//开启超时
const timeoutId = setTimeout(function () {
reject(new Error("fetch timeout"));
}, opts.timeout);
oldFetch(input, opts).then(
(res) => {
//清除超时
clearTimeout(timeoutId);
resolve(res);
},
(err) => {
//清除超时
clearTimeout(timeoutId);
reject(err);
}
);
});
};
function test() {
// get
fetch("http://127.0.0.1:3000/timeout", { timeout: 5 * 1000 })
.then((response) => response.text())
.then((text) => console.log("获取到的数据对象:", text))
.catch((err) => console.error("Request Failed", err));
}
document.getElementById("ajaxBtn").addEventListener("click", function () {
test();
});
</script>
</body>
Fetch同源携带Cookie
<body>
<button id="ajaxBtn">xhr 携带cookie</button>
<script>
function test() {
//2018年以后 默认值从 {"credentials":"omit"} 修改为 {"credentials":"same-origin"}
fetch("./a.png")
.then((response) => response.text())
.then((text) => console.log("获取到的数据对象:", text))
.catch((err) => console.log("Request Failed", err));
}
document.getElementById("ajaxBtn").addEventListener("click", function () {
test();
});
</script>
</body>
<body>
<button id="ajaxBtn">fetch 404错误码</button>
<script>
function test() {
fetch("http://127.0.0.1:3000/test3", {
credentials: "include",
mode: "cors",
})
.then((response) => {
console.log("请求成功status:", response.status);
return response.text();
})
.catch((err) => console.log("Request Failed", err));
}
document.getElementById("ajaxBtn").addEventListener("click", function () {
test();
});
</script>
</body>
function getXHR() {
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
//遍历IE中不同版本的ActiveX对象
let version = ["Msxml2", "Microsoft"];
for (let i = 0; i < version.length; i++) {
try {
xhr = new window.ActiveXObject(version[i] + ".XMLHTTP");
return;
} catch (e) {
console.log(e);
}
}
}
return xhr;
}
protocol + hostname + port
localStroage
,sessionStorage
和indexedDB
受限,cookie
以本域和父域为限制dom
获取受限ajax
受限script
、link
、img
、video
、object
、embed
、iframe
标签<script>
function jsonpCallback(data) {
console.log("我收到的数据了:", data);
}
</script>
<script src="http://127.0.0.1:3000/jsonp_request?callback=jsonpCallback"></script>
app.get("/jsonp_request", (_req, res) => {
const params = urlLib.parse(_req.url, true);
if (params.query && params.query.callback) {
const str = params.query.callback + "(" + JSON.stringify({ test: "服务端数据" }) + ")";
res.send(str);
} else {
res.send("Hello Yun");
}
// 可拿到回调函数的名称
console.log(params.query.callback);
});
JSONP缺点
GET
请求,不支持POST
等其他类型HTTP
请求(cross-origin sharing)
,是一种基于HTTP
头的机制origin
访问加载其资源如果携带身份凭证(cookie)
,服务器不得设置Access-Control-Allow-Origin
为通配符*
,应设置特定域
服务器不能将 Access-Control-Allow-Headers
的值设为通配符“*
”,而应将其设置为首部名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
服务器不能将 Access-Control-Allow-Methods
的值设为通配符“*
”,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET
let whitList = ["http://127.0.0.1:5500"]; //设置白名单
//设置跨域访问
app.use(function (req, res, next) {
const origin = req.headers.origin as string;
if (whitList.includes(origin)) {
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin", origin);
//允许携带凭证
res.header("Access-Control-Allow-Credentials", "true");
//允许的header类型
res.header("Access-Control-Allow-Headers", ["X-PINGOTHER", "content-type", "Origin", "Accept"]);
//允许浏览器访问的响应头
res.header("Access-Control-Expose-Headers", "test");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
//预检结果保存时间 1小时
res.header("Access-Control-Max-Age", `${5}`);
if (req.method.toLowerCase() == "options") {
res.send(204); //让 options 尝试请求快速结束
return;
}
}
next();
});
CORS中间件
let whitList = ["http://127.0.0.1:5500"]; //设置白名单
const corsOptions = {
origin: function (origin, callback) {
if (whitList.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true,
maxAge: 20,
allowedHeaders: ["X-PINGOTHER", "content-type", "Origin", "Accept"],
};
app.use(cors(corsOptions));
OPTIONS
方法发起一个预检请求到服务器,查看服务器是否允许发送实际请求服务端:
const WebSocket = require("ws");
const server = new WebSocket.Server({ port: 18000 });
server.on("open", function open() {
console.log("connected");
});
server.on("close", function close() {
console.log("disconnected");
});
server.on("connection", function connection(ws, req) {
// 发送欢迎信息给客户端
ws.send("服务器欢迎你链接");
ws.on("message", function incoming(message) {
// 广播消息给所有客户端
server.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send("服务器收到客户端消息 -> " + message);
}
});
});
});
客户端:
<style>
.txt {
font-size: 30px;
}
.inputBtn {
font-size: 40px;
}
</style>
<body>
<form onsubmit="return false;">
<h1>慕课聊天室:</h1>
<textarea id="repText" class="txt" style="width: 800px; height: 600px"></textarea>
<br />
<input
class="inputBtn"
type="text"
id="myInput"
name="message"
style="width: 300px"
value="Hello world"
/>
<input
class="inputBtn"
type="button"
id="mySend"
value="发送消息"
onclick="send(this.form.message.value)"
/>
</form>
<script type="text/javascript">
let socket;
const repTextEl = document.getElementById("repText");
if (window.WebSocket) {
socket = new WebSocket("ws://127.0.0.1:18000");
socket.onmessage = function (event) {
repTextEl.value = repTextEl.value + "\n" + event.data;
};
socket.onopen = function (event) {
repTextEl.value = "webSocket已链接";
};
socket.onclose = function (event) {
repTextEl.value = repTextEl.value + "连接被关闭";
};
} else {
console.log("浏览器不支持webSocket");
}
function send(message) {
if (!window.WebSocket) {
return;
}
if (socket.readyState == WebSocket.OPEN) {
socket.send(message);
} else {
console.log("webSocket还没有开启");
}
}
</script>
</body>
到此这篇关于深入学习JS XML和Fetch请求的文章就介绍到这了,更多相关JS XML和Fetch内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: 深入学习JS XML和Fetch请求
本文链接: https://lsjlt.com/news/167912.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0