フィードがタイムアウトしたときに「streamComplete」イベントを発行する socket.io ベースのウェブカメラ ストリーミング アプリケーションを作成しています。問題は、画像リソース リクエストが通常の AJAX リクエストと同じヘッダー/Cookie を送信していないように見えることです。これにより、socket.io がリクエストをソケットで識別できなくなり、後でストリームが完了したことをクライアントに伝えることができなくなるようです。
サーバー側には、mjpeg (moving jpeg) 画像を提供する node.js プロキシがあります。クライアントがアプリでフィードを選択すると、DOM の img 要素の 'src' 属性がカメラ フィードのルートを指すように変更されます。
この問題に対処しようとしているように見える HTML5 CORS 対応の画像仕様を調べましたが、私が知る限り、この機能はほとんどのブラウザーで完全には実装されていません。そうである場合、node.js 側でこれらのリクエストを許可する方法がわかりません。イメージに crossorigin='use-credentials' を追加するたびに、次のエラーが表示されます。
「クロスオリジン リソース共有ポリシーによって、クロスオリジン イメージの読み込みが拒否されました。」
サーバー側を制御しているので、明らかにそれを回避できるはずですが、次のノードヘッダールールは非常に緩和されているように見えますが、機能していないようです:
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With, XMLHttpRequest, X-HTTP-Method-Override, Content-Type");
res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, OPTIONS');
私が検討したオプションの 1 つは、イメージ リクエストに socketID を追加し、req.io.sockets.sockets[req.body.socketID] にリスナーを登録することです。それは少しハックに思えますが、競合状態などの他の懸念を引き起こす可能性があると確信しています. これは、これを達成しようとしているコードの一部です。
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({secret: 'blahblahblah'}));
// Allow all cross origin requests.
app.use(allowCrossOrigin);
app.get('/streams/:cam_id/:framerate', function(req, res,next) {
var camId = req.params.cam_id
, framerate = req.params.framerate
, type = (framerate === 0) ? 'jpeg' : 'mjpeg'
, reqString = 'http://blahblah.com/feeds/'
, proxy;
// Query database for stream info.
var query = new drupalInterface.Query(camId);
// When query comes back build the URL request string and create proxy.
query.on('results:available', function(results) {
var reqArr = [
results.site_name
, results.camera_name
, type
, framerate
];
reqString = reqString + reqArr.join('/') + '?status_frame=true&random=' + Math.random();
// Create new proxy for current client.
req.proxy = new MjpegProxy(reqString);
// Make request to telepresence server.
req.proxy.proxyRequest(req, res, next);
// Forward to express.io route for emitting stream event info to clients.
req.io.route('initializeProxyStream');
});
});
app.io.route('initializeProxyStream', function(req) {
var socket = app.io.sockets.sockets[req.query.socketID];
// If connecting directly to /stream don't try to listen for socket connection.
if(req.io) {
req.proxy.once('streamComplete', function() {
socket.emit('streamComplete');
});
}
});
私がやっていることにexpress.ioが必要かどうかはわかりませんが、この文脈では理にかなっているようです。
crossorigin 属性で正しい軌道に乗っていましたか? 不足しているミドルウェアはありますか?