nodejs

Node.jsでStreamのデータを必ずBufferで受け取る

ShiftJISお前は絶対許さん

Node.jsで例えばhttpモジュールのrequest等を使う時、どうしてもBufferのchunkを受け取りたいときがあります。(例えば文字コードがShift-JISのテキストファイルのダウンロードとか。)

この時いろいろな指定があるものの全く効かないときに、必ずBufferで受け取る方法を書いておきます。

Streamで絶対にBufferで受け取る

const stream   = require( 'stream' );
const buftrans = new stream.Transform( { transform( chunk, encoding, callback ) { callback( null, chunk ); } } );

stream.Transformはデータを変換するStreamで、ここで何もしないと必ずBufferを受け取れます。
つまり受け取ったデータをそのまま返せば、Bufferを返せます。

使用例

Promise<Buffer>で返すGet。

例えばShiftJISのテキストファイルを取得して、iconvにかける時に、Bufferだと扱いやすいです。

var stream   = require( 'stream' );
var http     = require( 'http' );
function Get( url: string )
{
    const buftrans = new stream.Transform( { transform( chunk, encoding, callback ) { callback( null, chunk ); } } );

    return new Promise( ( resolve, reject ) =>
    {
        const bufs: Buffer[] = [];
        http.get( url, ( response ) => { response.pipe( buftrans ); } );
        buftrans.on( 'data', ( chunk ) => { bufs.push( chunk ); } );
        buftrans.on( 'end', () => { resolve( Buffer.concat( bufs ) ); } );
        buftrans.on( 'error', ( error ) => { reject( error ); } );
    } );
}

http.createServerで新規でリクエストしたデータを文字列処理せずレスポンスとして返す

例えばプロキシサーバーを作っているとき、ShiftJISのサイトを開いても、そのままブラウザに文字列処理せず渡すので、ブラウザが頑張ってくれます。

var stream   = require( 'stream' );
var http     = require( 'http' );

function ProxyServerStart( settings )
{
    var server = http.createServer();
    server.on( 'request', function ( request, response )
    {
        http.request( 'NEW URL', ( res ) =>
        {
            const buftrans = new stream.Transform( { transform( chunk, encoding, callback ) { callback( null, chunk ); } } );

            res.pipe( buftrans );
            buftrans.on( 'data', ( chunk ) => { response.write( chunk ); } );
            buftrans.on( 'end', () => { response.end(); } );
            buftrans.on( 'error', ( error ) => { response.end(); } );
            Object.keys( res.headers ).forEach( ( key ) =>
            {
                response.setHeader( key, res.headers[ key ] );
            } );
        } );
        request.on( 'data', ( data ) => { hreq.write( data ); } );
        request.on( 'end', () => { hreq.end(); } );
    } );
    server.listen( settings.port, settings.host );
}

ProxyServerStart({ host: 'localhost', port: 8080 });

まとめ

ShiftJIS滅びろ