通过HTTP流从浏览器到服务器的数据的方法 [英] Method for streaming data from browser to server via HTTP

查看:407
本文介绍了通过HTTP流从浏览器到服务器的数据的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有任何XHR样的浏览器的API可以通过HTTP?

Are there any XHR-like browser APIs available for streaming binary to a server over HTTP?

我想打一个HTTP PUT请求和编程方式创建的数据,随着时间的推移。我不想一次创建所有这些数据,因为有可能是内存里面的它演出。有些psueudo- code来说明什么,我在得到:

I want to make an HTTP PUT request and create data programmatically, over time. I don't want to create all this data at once, since there could be gigs of it sitting in memory. Some psueudo-code to illustrate what I'm getting at:

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);
});

我目前已经制定,而不是一个网络接口解决方案,但将preFER普通的HTTP与一些现有的服务器端code更好的互操作。

I currently have a web socket solution in place instead, but would prefer regular HTTP for better interop with some existing server-side code.

编辑:我可以用最前沿的浏览器的API。我一直在寻找在提取API,因为它支持ArrayBuffers,DataViews的,文件和这样的请求主体。如果我能以某种方式伪造了这些对象之一,这样我可以使用API​​获取动态数据,将工作对我来说。我试图创建一个代理对象,看看是否有方法被称为,我可以猴子补丁。不幸的是,它似乎在浏览器(至少在铬)正在做本土code,而不是在JS地阅读。但是,请纠正我,如果我错了这一点。

I can use bleeding edge browser APIs. I was looking at the Fetch API, as it supports ArrayBuffers, DataViews, Files, and such for request bodies. If I could somehow fake out one of these objects so that I could use the Fetch API with dynamic data, that would work for me. I tried creating a Proxy object to see if any methods were called that I could monkey patch. Unfortunately, it seems that the browser (at least in Chrome) is doing the reading in native code and not in JS land. But, please correct me if I'm wrong on that.

推荐答案

我不知道如何与纯HTML5 API的做到这一点,但一个可能的解决办法是使用Chrome应用作为后台服务来提供额外的功能,的网页。如果你已经愿意使用浏览器的发展,使实验性功能,这似乎是只比增量一步。

I don't know how to do this with pure HTML5 APIs, but one possible workaround is to use a Chrome App as a background service to provide additional features to a web page. If you're already willing to use development browsers and enable experimental features, this seems like just an incremental step further than that.

Chrome应用可以调用 chrome.sockets.tcp API,可以在其上实现你想要的任何协议,包括HTTP和HTTPS。这将提供为执行流的灵活性。

Chrome Apps can call the chrome.sockets.tcp API, on which you can implement any protocol you want, including HTTP and HTTPS. This would provide the flexibility to implement streaming.

一个普通网页可以与一个应用程序使用 chrome.runtime <交换消息/ code> API,只要在App 声明这种用法。这将使你的网页,使您的应用程序异步调用。

A regular web page can exchange messages with an App using the chrome.runtime API, as long as the App declares this usage. This would allow your web page to make asynchronous calls to your App.

我写了这个简单的应用程序作为一个概念证明:

I wrote this simple App as a proof of concept:

的manifest.json

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": [
  ]
}

background.js

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);
        });
      }
    }
  });
});

该应用程序不具有用户界面。它用于监听连接,使一个硬codeD PUT请求 http://httpbin.org/put httpbin 是一个有用的测试网站,但请记呢不支持分块编码)。该PUT数据(目前硬coded到恰好17个字节)从客户端流中(根据需要使用尽可能少或一样多的消息),并发送至服务器。来自服务器的响应被流传输回客户机

This App does not have a user interface. It listens for connections and makes a hard-coded PUT request to http://httpbin.org/put (httpbin is a useful test site but note it does not support chunked encoding). The PUT data (currently hard-coded to exactly 17 octets) is streamed in from the client (using as few or as many messages as desired) and sent to the server. The response from the server is streamed back to the client.

这只是一个概念验证。一个真正的应用程序或许应该:

This is just a proof of concept. A real App should probably:


  • 连接到任何主机和端口。

  • 使用传输编码:分块

  • 信号流数据的末尾。

  • 拉手套接字错误。

  • 支持TLS(例如,与锻造

  • Connect to any host and port.
  • Use Transfer-Encoding: chunked.
  • Signal the end of streaming data.
  • Handle socket errors.
  • Support TLS (e.g. with Forge)

下面是一个使用应用程序作为服务(请注意,你必须配置自己的应用程序ID)样本网页进行流上传(17个字节):

Here is a sample web page that performs a streaming upload (of 17 octets) using the App as a service (note that you will have to configure your own App 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>

当我安装了Chrome浏览器的应用程序加载此网页,httpbin返回:

When I load this web page in a Chrome browser with the App installed, httpbin returns:

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"
}

这篇关于通过HTTP流从浏览器到服务器的数据的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆