LoginSignup
9
7

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-03-27

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滅びろ

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7