常见请求方式

12 阅读8分钟

常见请求方式

主要介绍了几种前端常见的请求方式:

  1. xhr
  2. fetch
  3. websocket
  4. eventsource
  5. sendBeacon
  6. 常见标签请求

1. DOM标签

在HTML中,有很多标签可以用来发起HTTP请求。以下是最常见的一些:

  1. <a>:此标签用于创建一个链接,当用户点击链接时将发起请求到指定的URL。

    html
    复制代码
    <a href="http://example.com">Visit Example</a>
    
  2. <img>:此标签用于加载图片,浏览器会发送请求去获取对应的src的图片资源。

    html
    复制代码
    <img src="image.jpg" alt="My test image">
    
  3. <link>:此标签通常位于HTML文件的<head>部分,用于引入CSS文件。

    html
    复制代码
    <link rel="stylesheet" type="text/css" href="styles.css">
    
  4. <script>:此标签用于引入JavaScript文件。

    html
    复制代码
    <script src="script.js"></script>
    
  5. <iframe>:此标签用于嵌入另一个HTML页面。

    html
    复制代码
    <iframe src="http://example.com"></iframe>
    
  6. <video> and <audio>:这两个标签用于嵌入视频和音频内容。

    html
    复制代码
    <video src="myVideo.mp4" controls></video>
    <audio src="myAudio.mp3" controls></audio>
    
  7. <object><embed><source>等也能发起请求。

请注意,以上的所有请求都是浏览器根据HTML内容自动发起的,不需要做额外的配置。

如果使用js进行获取呢?

JavaScript 并不能直接获取到HTML标签请求的结果,但可以通过监听事件和使用一些DOM 属性来间接得到一些信息。以下是一些常见的方法:

  1. 以img为例,为图像添加 load 和 error 事件:
ini
复制代码
javascript复制代码
var img = new Image();
img.src = 'http://example.com/image.jpg';
img.onload = function() {
    console.log('Image has loaded');
};
img.onerror = function() {
    console.log('An error occurred while loading image');
};

我们并没有直接获取到图片的内容,但是我们知道图片何时加载成功,或者是否出错,可以获取返回的内容。

2. AJAX

2.1 概念

AJAXAsynchronous JavaScript and XML的缩写,即异步的JavaScript和XML。它是一种在不重新加载整个网页的情况下,与服务器交换数据并更新部分网页的技术。

AJAX的核心是XMLHttpRequest对象,它提供了一个API,使得浏览器可以通过JavaScript向服务器发送请求并接收响应。 XMLHttpRequest是一个浏览器对象,用于在不重新加载页面的情况下向服务器发送HTTP请求并获取响应。它是AJAX技术的核心组成部分之一,用于实现异步数据交互。

2.2 案例

  1. 请求过程
markdown
复制代码
1. 创建ajax对象 
2. 调用ajax对象的open 函数  准备发送请求 
3. 调用ajax对象的send 函数  发送请求  但是请求还没有到达服务器 
4. 调用ajax对象的监听函数 onreadystatechange   监听ajax的创建过程 
      readystate  ajax 的状态码 
        0  准备创建ajax
              new XMLHttpRequest();
        1  发送了请求  服务器尚未接到数据 [客户端和服务器   建立了链接]
              open()
              send()
        以下这些状态码 都是服务器对客户端数据进行操作的状态     
        2  发送了请求  服务器接受到了请求 

        3  服务器接收到了请求 并且在处理请求 

        4  服务器处理请求成功  响应给客户端 

      status  相应状态码  表示 readystate === 4 
         服务器已经向客户端响应了数据 
           状态码 会判断 服务器相应数据的状态 
             200 ok   响应成功 
             404      响应的页面没有找到 
             500      服务器产生异常 失败
  1. 案例
js
复制代码
<button id="btn">获取数据</button>
<h1 id="h1">
	希望获取新加载的数据
</h1>
<div id="content">
	原有的数据........
</div>
<script>

	// 注册事件
	const btnNode = document.querySelector("#btn");
	const contentNode = document.getElementById('content')

	// 注册onclick事件 
	btnNode.onclick = function () {
		// 1. 创建ajax 对象 
		// 高版本浏览器创建的对象 
		let xhr;
		if (window.XMLHttpRequest) {
			xhr = new XMLHttpRequest();
		} else {
			// IE5  IE6 低版本浏览器 
			xhr = new ActiveXObject("Microsoft.XMLHTTP")
		}

		// 2. 准备发送请求 
		/*
		参数
			1.  请求方式  get/post/put/delete
			2.  请求位置  url
			3.  是否是异步请求 
						 true  表示异步
						 false 表示同步
		*/
		xhr.open("POST", "http://localhost:3000/api/xhr", true)
		// 设置请求头
		xhr.setRequestHeader("token", "888888888")

		// 3. 发送请求 
		xhr.send()

		// 4.  监听ajax的整个过程
		// onreadystatechange 监听ajax 发送的事件 
		xhr.onload = function () {
			console.log('打印***onload')
			const data = xhr.responseText;
			//获取h1 节点 
			const h1Node = document.getElementById("h1")
			h1Node.innerText = data;
			console.log(data);
		}
	}
</script>

image.png 其中第四步可以使用xhr.onload进行替换

js
复制代码
xhr.onload = function(){
    const data = xhr.responseText;
    //获取h1 节点 
    const h1Node = document.getElementById("h1")
    h1Node.innerText = data;
    console.log(data);
}

2.3 xhr.onloadxhr.onreadystatechange两者的区别

xhr.onloadxhr.onreadystatechange执行相同的操作:在一个异步请求的各种生命周期阶段接收通知。但是,它们的使用方式有一些差异。

xhr.onreadystatechange:

onreadystatechange事件会在readyState属性值改变时触发。这意味着你需要检查readyState值并确定请求是否完成。如果readyState等于4,那么请求已经完成并且响应已经就绪。

ini
复制代码
javascript复制代码
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(xhr.responseText);
    }
};

xhr.onload:

相比之下,xhr.onload事件只在请求成功完成时触发。不需要检查readyState或状态代码,因为如果触发了onload事件,那么就可以确保请求已经成功完成。

ini
复制代码
javascript复制代码
xhr.onload = function() {
    console.log(xhr.responseText);
};

xhr.onload提供了一个更简洁、更直观的方式来处理成功的HTTP请求。然而,如果你需要更细粒度的控制(例如,你想在请求的不同阶段执行不同的操作),那么xhr.onreadystatechange可能会是一个更好的选择。

2.4 基于ajax封装的库有axios

3. fetch

3.1 概念

Fetch 是 XMLHttpRequest 的升级版,用于在 JavaScript 脚本里面发出 HTTP 请求。

3.2 案例

js
复制代码
<button id="btn">获取数据</button>
<h1 id="h1">
	希望获取新加载的数据
</h1>
<div id="content">
	原有的数据........
</div>
<script>

	// 注册事件
	const btnNode = document.querySelector("#btn");

	// 注册onclick事件 
	btnNode.onclick = function () {
		fetch('http://localhost:3000/api/fetch', {
			headers: {
				token: '66666666666'
			}
		}).then(res => {
			return res.text()
		}).then(data => {
			const h1Node = document.getElementById("h1")
			h1Node.innerText = data;
		})

	}

</script>

image.png

3.3 基于fetch封装的库umi-request


总结ajax和fetch区别

功能点XHRFetch
基本请求、获取响应能力
监控请求进度x
监控响应进度
Service-Worker中是否可用x
控制cookie的携带x
控制重定向x
请求取消
自定义referrerx
x
API风格EventPromise
活跃度x

4. websocket

4.1 概念

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以直接创建持久性的连接,并进行双向数据传输。

现在许多网站的实时功能(例如聊天,实时游戏等)都是使用 WebSocket 实现的。它解决了 HTTP 协议只能由客户端向服务端发起请求的问题,使得服务端也能主动向客户端发送数据。

4.2 案例

js
复制代码
<button id="btn">获取数据</button>
<h1 id="h1">
	希望获取新加载的数据
</h1>
<div id="content">
	原有的数据........
</div>
<script>

	// 注册事件
	const btnNode = document.querySelector("#btn");
	const h1Node = document.getElementById("h1")

	// 注册onclick事件 
	btnNode.onclick = function () {

		const socket = new WebSocket('ws://localhost:3000');

		socket.onopen = function () {
			console.log('连接已建立');
		};

		socket.onmessage = function (event) {
			const data = event.data;
			console.log('接收到服务器发送的消息:', data);
			h1Node.innerText = data;
		};

		socket.onclose = function () {
			console.log('连接已关闭');
		};
		// 心跳
		setInterval(() => {
			socket.send('ping');
		}, 3000);

}
</script>

image.png

4.3 基于websocket 封装的库socket.io

5. Beacon

5.1 概念

Beacon API 用于发送异步和非阻塞请求到服务器。这类请求不需要响应。与 XMLHttpRequest 或 Fetch API 请求不同,浏览器会保证在页面卸载前,将信标请求初始化并运行完成。

Beacon API 的优点是,它可以在浏览器关闭或离开当前页面时异步发送数据到服务器,而不会阻塞页面的操作或等待服务器的响应。这对于进行统计分析、性能监控和日志记录等后台数据收集的场景非常有用。

5.2 案例

js
复制代码
<button id="btn">获取数据</button>
<h1 id="h1">
	希望获取新加载的数据
</h1>
<div id="content">
	原有的数据........
</div>
<script>

	// 注册事件
	const btnNode = document.querySelector("#btn");
	const h1Node = document.getElementById("h1")

	// 注册onclick事件 
	btnNode.onclick = function () {
		const data = {
			event: '按钮点击',
			timestamp: new Date().toISOString(),
			userAgent: navigator.userAgent
		};
		// 调用发送数据的函数, 返回true
	  const res =  navigator.sendBeacon('http://localhost:3000/api/beacon', JSON.stringify(data))
		h1Node.innerText = res
	}

</script>

image.png

6. SSE(Eventsource)

6.1 概念

Server-Sent Events(SSE)是一种基于HTTP的服务器向客户端发送更新的技术。与WebSockets类似,SSE也允许服务器向客户端推送实时更新。然而,不同于WebSockets提供的双向通信,SSE是单向的:只允许服务器向客户端发送数据。

SSE 是基于HTTP的,因此比WebSocket更容易使用,并且与现有的HTTP基础设施兼容性更好。使用SSE,你可以使用传统的HTTP请求到服务器上开启一个持久连接,服务器可以通过这个连接连续地发送消息。

6.2 案例

js
复制代码
<button id="btn">获取数据</button>
<h1 id="h1">
	希望获取新加载的数据
</h1>
<div id="content">
	原有的数据........
</div>
<script>

	// 注册事件
	const btnNode = document.querySelector("#btn");
	const h1Node = document.getElementById("h1")

	// 注册onclick事件 
	btnNode.onclick = function () {
		// 创建一个EventSource对象,连接到服务器端的SSE端点
		const eventSource = new EventSource('http://localhost:3000/api/sse');

		// 监听服务器端发送的消息
		eventSource.onmessage = (event) => {
			console.log(event.data);
			const data = event.data
			h1Node.innerText = data;
			// 在这里处理服务器端发送的消息
		};

		// 监听连接关闭事件
		eventSource.onclose = () => {
			console.log('SSE connection closed');
		};

		// 监听错误事件
		eventSource.onerror = (error) => {
			console.error('SSE error:', error);
		};
	}
</script>

image.png


7. 以上案例服务端代码

使用koa进行编写:

js
复制代码
const Koa = require('koa')
const Router = require('koa-router')
const websockify = require('koa-websocket')
const cors = require('koa2-cors')
const { koaBody } = require('koa-body');

const app = new Koa();

app.use(koaBody());


// 使用koa2-cors中间件解决跨域
app.use(cors())

const router = new Router()

//  使用 koa-websocket 将应用程序升级为 WebSocket 应用程序
const appWebSocket = websockify(app)

// webSocket
appWebSocket.ws.use((ctx, next) => {
	// 存储新连接的客户端
	clients.add(ctx.websocket)
	// 处理连接关闭事件
	ctx.websocket.on('close', () => {
		clients.delete(ctx.websocket)
	})
	ctx.websocket.on('message', (data) => {
		console.log('打印***data', data)
		ctx.websocket.send('pong' + Math.random())
	})
	ctx.websocket.on('error', (err) => {
		console.log('打印***err', err)
		clients.delete(ctx.websocket)
	})

	return next(ctx)
})

// xhr
router.post('/api/xhr', (ctx) => {
	ctx.body = 'I am xhr!'
})
// fetch
router.get('/api/fetch', (ctx) => {
	ctx.body = 'I am fetch!'
})
// beacon
router.post('/api/beacon', (ctx) => {
	const data = ctx.request.body
	console.log('打印***data', data)
	ctx.body = 'I am beacon!'
})
// sse
router.get('/api/sse', (ctx) => {

	ctx.respond = false
	ctx.res.writeHead(200, {
		"Content-Type": "text/event-stream",
		"Cache-Control": "no-cache",
		Connection: "keep-alive",
	});

	// 发送初始事件数据
	ctx.res.write(`data: I am sse!\n\n`);

	// 定期发送事件数据
	setInterval(() => {
		ctx.res.write(`data: This is a SSE message at ${new Date().toISOString()}\n\n`);
	}, 1000);
})

// 将路由注册到应用程序
appWebSocket.use(router.routes()).use(router.allowedMethods())

// 启动服务器
appWebSocket.listen(3000, () => {
	console.log('Server started on port 3000')
})