Bra*_*rad 11 javascript browser http xmlhttprequest
是否有类似XHR的浏览器API可用于通过HTTP将二进制文件流式传输到服务器?
我希望随着时间的推移制作HTTP PUT请求并以编程方式创建数据.我不想一次创建所有这些数据,因为它可能会在内存中出现.一些psueudo代码来说明我所得到的:
var dataGenerator = new DataGenerator(); // Generates 8KB UInt8Array every second
var streamToWriteTo;
http.put('/example', function (requestStream) {
streamToWriteTo = requestStream;
});
dataGenerator.on('data', function (chunk) {
if (!streamToWriteTo) {
return;
}
streamToWriteTo.write(chunk);
});
Run Code Online (Sandbox Code Playgroud)
我现在有一个Web套接字解决方案,但更喜欢常规HTTP,以便更好地与一些现有的服务器端代码互操作.
编辑:我可以使用最前沿的浏览器API.我正在查看Fetch API,因为它支持请求体的ArrayBuffers,DataViews,Files等.如果我能以某种方式伪造其中一个对象,以便我可以使用动态数据的Fetch API,这对我有用.我尝试创建一个Proxy对象,看看是否有任何方法被调用,我可以修补.不幸的是,似乎浏览器(至少在Chrome中)正在使用本机代码而不是JS版本进行读取.但是,如果我错了,请纠正我.
我不知道如何使用纯HTML5 API来执行此操作,但是一种可能的解决方法是将Chrome应用程序用作后台服务,以向网页提供其他功能。如果您已经愿意使用开发浏览器并启用实验性功能,那么这似乎只是一个进一步的步骤。
Chrome Apps可以调用chrome.sockets.tcp
API,您可以在该API上实现所需的任何协议,包括HTTP和HTTPS。这将提供实现流的灵活性。
常规网页可以使用chrome.runtime
API 与应用程序交换消息,只要该应用程序声明此用法即可。这将允许您的网页对应用程序进行异步调用。
我写了这个简单的应用程序作为概念证明:
manifest.json
{
"manifest_version" : 2,
"name" : "Streaming Upload Test",
"version" : "0.1",
"app": {
"background": {
"scripts": ["background.js"]
}
},
"externally_connectable": {
"matches": ["*://localhost/*"]
},
"sockets": {
"tcp": {
"connect": "*:*"
}
},
"permissions": [
]
}
Run Code Online (Sandbox Code Playgroud)
background.js
var mapSocketToPort = {};
chrome.sockets.tcp.onReceive.addListener(function(info) {
var port = mapSocketToPort[info.socketId];
port.postMessage(new TextDecoder('utf-8').decode(info.data));
});
chrome.sockets.tcp.onReceiveError.addListener(function(info) {
chrome.sockets.tcp.close(info.socketId);
var port = mapSocketToPort[info.socketId];
port.postMessage();
port.disconnect();
delete mapSocketToPort[info.socketId];
});
// Promisify socket API for easier operation sequencing.
// TODO: Check for error and reject.
function socketCreate() {
return new Promise(function(resolve, reject) {
chrome.sockets.tcp.create({ persistent: true }, resolve);
});
}
function socketConnect(s, host, port) {
return new Promise(function(resolve, reject) {
chrome.sockets.tcp.connect(s, host, port, resolve);
});
}
function socketSend(s, data) {
return new Promise(function(resolve, reject) {
chrome.sockets.tcp.send(s, data, resolve);
});
}
chrome.runtime.onConnectExternal.addListener(function(port) {
port.onMessage.addListener(function(msg) {
if (!port.state) {
port.state = msg;
port.chain = socketCreate().then(function(info) {
port.socket = info.socketId;
mapSocketToPort[port.socket] = port;
return socketConnect(port.socket, 'httpbin.org', 80);
}).then(function() {
// TODO: Layer TLS if needed.
}).then(function() {
// TODO: Build headers from the request.
// TODO: Use Transfer-Encoding: chunked.
var headers =
'PUT /put HTTP/1.0\r\n' +
'Host: httpbin.org\r\n' +
'Content-Length: 17\r\n' +
'\r\n';
return socketSend(port.socket, new TextEncoder('utf-8').encode(headers).buffer);
});
}
else {
if (msg) {
port.chain = port.chain.then(function() {
// TODO: Use chunked encoding.
return socketSend(port.socket, new TextEncoder('utf-8').encode(msg).buffer);
});
}
}
});
});
Run Code Online (Sandbox Code Playgroud)
该应用程序没有用户界面。它侦听连接,并向发出硬编码的PUT请求http://httpbin.org/put
(httpbin是一个有用的测试站点,但请注意,它不支持分块编码)。PUT数据(当前硬编码为17个八位位组)从客户端流式传输(使用所需的消息数量少或多)并发送到服务器。来自服务器的响应被流回客户端。
这仅仅是概念的证明。真正的应用程序可能应该:
这是一个示例网页,使用该应用程序作为服务执行流式上传(17个八位字节)(请注意,您必须配置自己的应用程序ID):
<pre id="result"></pre>
<script>
var MY_CHROME_APP_ID = 'omlafihmmjpklmnlcfkghehxcomggohk';
function streamingUpload(url, options) {
// Open a connection to the Chrome App. The argument must be the
var port = chrome.runtime.connect(MY_CHROME_APP_ID);
port.onMessage.addListener(function(msg) {
if (msg)
document.getElementById("result").textContent += msg;
else
port.disconnect();
});
// Send arguments (must be JSON-serializable).
port.postMessage({
url: url,
options: options
});
// Return a function to call with body data.
return function(data) {
port.postMessage(data);
};
}
// Start an upload.
var f = streamingUpload('https://httpbin.org/put', { method: 'PUT' });
// Stream data a character at a time.
'how now brown cow'.split('').forEach(f);
</script>
Run Code Online (Sandbox Code Playgroud)
当我在安装了应用程序的Chrome浏览器中加载此网页时,httpbin返回:
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 19 Jun 2016 16:54:23 GMT
Content-Type: application/json
Content-Length: 240
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"args": {},
"data": "how now brown cow",
"files": {},
"form": {},
"headers": {
"Content-Length": "17",
"Host": "httpbin.org"
},
"json": null,
"origin": "[redacted]",
"url": "http://httpbin.org/put"
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我目前正在搜索完全相同的东西(通过Ajax上游)。我目前发现的结果似乎就像我们在浏览器功能设计的前沿时一样;-)
XMLHttpRequest定义在第4步中告诉bodyinit,其内容提取是(或可以是)可读流。
我仍在(以非Web开发人员的身份)搜索有关如何创建此类事物并将数据馈入该“可读流”(即应为“可写流”)的“另一端”的信息,但是我确实做到了找不到)。
也许您会更好地进行搜索,如果找到了实现这些设计计划的方法,则可以在此处发布。
^ 5
斯文
您可以使用Promise
, setTimeout
, 递归。另请参阅REST 中的 PUT 与 POST
var count = 0, total = 0, timer = null, d = 500, stop = false, p = void 0
, request = function request () {
return new XMLHttpRequest()
};
function sendData() {
p = Promise.resolve(generateSomeBinaryData()).then(function(data) {
var currentRequest = request();
currentRequest.open("POST", "http://example.com");
currentRequest.onload = function () {
++count; // increment `count`
total += data.byteLength; // increment total bytes posted to server
}
currentRequest.onloadend = function () {
if (stop) { // stop recursion
throw new Error("aborted") // `throw` error to `.catch()`
} else {
timer = setTimeout(sendData, d); // recursively call `sendData`
}
}
currentRequest.send(data); // `data`: `Uint8Array`; `TypedArray`
return currentRequest; // return `currentRequest`
});
return p // return `Promise` : `p`
}
var curr = sendData();
curr.then(function(current) {
console.log(current) // current post request
})
.catch(function(err) {
console.log(e) // handle aborted `request`; errors
});
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5794 次 |
最近记录: |