XmlHttpRequest responseType: ‘stream‘ 图片代理服务器
它是一个存在于原生
XMLHttpRequest
对象中的属性。在 Web API 中,XMLHttpRequest
对象用于发送 HTTP 或 HTTPS 请求到服务器,并接收响应。responseType
属性就是用来指定预期从服务器返回的响应数据的类型。
默认值
responseType的默认值为json,它还有其他可选值
-
'arraybuffer':表示服务器响应预计是 ArrayBuffer 形式,对于处理二进制数据非常有用。
-
'blob':表示服务器响应预计是二进制大对象(Blob)形式,通常用于处理文件或图像。
-
'document':表示服务器响应预计是一个 HTML Document 或 XML Document,这取决于接收到的数据的 MIME 类型。
-
'json':这是默认设置。表示服务器响应预计是 JSON 格式的。
-
'text':表示服务器响应预计是文本形式,包含在 DOMString 对象中。
-
'stream':在某些实现中,这个值允许你以流的形式接收响应数据,这在处理大文件或实时数据流时特别有用。在数据传输过程中就能读取已经下载的数据,而不是等到所有数据都下载完成
-
空字符串 (''):当
responseType
为空字符串时,它通常会采用默认类型,即 'text'。
responseType: 'stream'
的作用
-
内存优化:对于大文件或大量数据,将其全部加载到内存中可能会导致内存溢出或性能问题。通过设置
responseType: 'stream'
,你可以按需处理数据,每次只处理一小部分,从而有效管理内存使用。 -
实时处理:对于实时数据流,如视频流或实时日志,使用流可以确保你能够实时接收并处理数据,而不是等待整个数据流结束后再处理。
-
灵活性:通过流,你可以使用各种流处理库或工具来进一步处理数据,如转换、压缩、加密等。
-
错误处理:当使用流时,你可以监听错误事件,以便在数据传输过程中发生错误时进行处理。
在 Node.js 中,你可以使用流(Stream)的 API 来进一步操作这些数据,例如使用 .pipe()
方法将数据直接传输到另一个流(如文件写入流)或进行其他操作。
图片代理服务器
代理图片时候,如果需要等待图片下载完成才给客户端相遇数据,这样太慢了。如果在下载图片过程中就把数据推送给客户的,这样可以提高响应速度。
代码
const http = require('http');
const https = require('https');
const url = require('url');
const PORT = 3000; // 你的代理服务器端口
const httpTool = (url, cb) => {
console.log("https?", url.startsWith("https"), url)
let ishttps = url.startsWith("https");
if (ishttps) {
return https.get(url, cb);
}
else {
return http.get(url, cb);
}
}
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
console.log("href", parsedUrl.query.url)
const targetPath = parsedUrl.query.url;
// 创建一个请求到原始图片服务器
const targetReq = httpTool(targetPath, (targetRes) => {
// 将原始服务器的响应转发给客户端
res.writeHead(targetRes.statusCode, targetRes.headers);
console.log("流数据接受中..")
targetRes.pipe(res);
});
targetReq.on('error', (err) => {
console.error(`请求 ${targetPath} 时出错:`, err);
res.writeHead(500);
res.end('图片代理服务器内部错误');
});
});
server.listen(PORT, () => {
console.log(`图片代理服务器正在运行,监听端口 ${PORT}`);
});
命令行
命令执行node index.js,
文件本地起一个端口3000的代理服务器,拦截所有请求
客户端请求地址
query url是要请求的真实图片
http://localhost:3000/?url=https://www.runoob.com/images/pulpit.jpg
这种方式可以避免浏览器跨域,更加细致的代理插件 http-proxy-middleware
xmlhttprequest使用 stream
const xhr = new XMLHttpRequest();
// 设置响应类型为流
xhr.responseType = 'stream';
// 打开请求
xhr.open('GET', 'http://example.com/large-file', true);
// 注册 onload 事件处理程序
xhr.onload = function () {
if (this.status === 200) {
// 获取响应流
const reader = this.response;
const stream = reader.getReader();
// 读取流中的数据块
function read() {
stream.read().then(({ value, done }) => {
// 如果还有数据,处理 value(它是一个 Uint8Array)
if (value) {
// 在这里处理数据块,例如写入文件或进行其他操作
console.log(value);
// 继续读取流中的下一个数据块
read();
} else {
// 所有数据都已读取完毕
console.log('Stream reading complete.');
}
}).catch(error => {
console.error('Error reading stream:', error);
});
}
// 开始读取流
read();
} else {
console.error('Request failed with status', this.status);
}
};
// 注册 onerror 事件处理程序
xhr.onerror = function () {
console.error('Request failed');
};
// 发送请求
xhr.send();
axios使用stream
const express = require('express');
const axios = require('axios'); // 用于发送 HTTP 请求
const app = express();
const PORT = 3000; // 代理服务器端口
// 配置 Express 应用
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
// 代理图片请求的中间件
function proxyImage(req, res, next) {
const targetUrl = `http://example.com${req.originalUrl}`; // 构造目标 URL
axios({
method: 'get',
url: targetUrl,
responseType: 'stream', // 响应类型设置为流
})
.then((response) => {
// 设置响应头
const headers = response.headers;
delete headers['content-length']; // 删除 content-length,因为流的长度未知
res.set(headers);
// 将响应流转发给客户端
response.data.pipe(res);
})
.catch((error) => {
console.error('Error fetching image:', error);
res.status(500).send('Error fetching image');
});
}
// 应用代理图片请求的中间件
app.use('/images', proxyImage); // 所有以 '/images' 开头的请求都会被代理
// 启动服务器
app.listen(PORT, () => {
console.log(`图片代理服务器正在运行,监听端口 ${PORT}`);
});