如何使用nodejs提供图像

时间:2011-04-28 19:08:37

标签: node.js

我有一个位于public / images / logo.gif的徽标。这是我的nodejs代码。

http.createServer(function(req, res){
  res.writeHead(200, {'Content-Type': 'text/plain' });
  res.end('Hello World \n');
}).listen(8080, '127.0.0.1');

它有效,但当我要求localhost:8080 / logo.gif时,我显然没有得到徽标。

我需要做些什么更改才能投放图片。

12 个答案:

答案 0 :(得分:146)

我同意其他海报,最终,你应该使用一个框架,比如Express ..但首先你应该也理解如何在没有图书馆的情况下做一些基本的事情,真正理解图书馆为你抽象的东西..步骤是

  1. 解析传入的HTTP请求,以查看用户要求的路径
  2. 在条件语句中添加路径以供服务器响应
  3. 如果请求图像,请从磁盘读取图像文件。
  4. 在标题中提供图像内容类型
  5. 在身体中提供图像内容
  6. 代码看起来像这样(未经测试)

    fs = require('fs');
    http = require('http');
    url = require('url');
    
    
    http.createServer(function(req, res){
      var request = url.parse(req.url, true);
      var action = request.pathname;
    
      if (action == '/logo.gif') {
         var img = fs.readFileSync('./logo.gif');
         res.writeHead(200, {'Content-Type': 'image/gif' });
         res.end(img, 'binary');
      } else { 
         res.writeHead(200, {'Content-Type': 'text/plain' });
         res.end('Hello World \n');
      }
    }).listen(8080, '127.0.0.1');
    

答案 1 :(得分:146)

2016年更新

使用Express和不使用Express的示例实际工作

这个问题已超过5年,但每个答案都有一些问题

TL; DR

向下滚动以查看示例以使用以下内容投放图像:

  1. express.static
  2. express
  3. connect
  4. http
  5. net
  6. 所有示例也在GitHub上:https://github.com/rsp/node-static-http-servers

    测试结果可在Travis上获得:https://travis-ci.org/rsp/node-static-http-servers

    简介

    自问这个问题超过5年后,只有{{3>} generalhenry ,但即使答案没有问题,但似乎有一些问题接收即可。有评论说除了如何依赖别人完成工作之外"并没有解释其他事情以及有多少人投了这个评论的事实清楚地表明很多事情需要澄清。

    首先,回答"如何使用Node.js提供图像"没有从头开始实施静态文件服务器并且做得很糟糕。一个很好的答案是使用类似Express的模块 正确完成工作

    回答评论说使用Express "除了如何依赖别人完成工作之外没有其他解释" 应该注意,使用http模块已经依赖其他人来完成工作。如果有人不想依赖任何人完成工作,那么应该使用至少原始TCP套接字 - 我在下面的一个例子中做了这一点。

    更严重的问题是,使用http模块的所有答案都是已损坏。它们会引入竞争条件不安全的路径解析,这将导致路径遍历漏洞阻止I / O 完全无法满足任何并发请求所有和其他微妙问题 - 它们完全被打破,作为问题所要求的例子,但他们已经使用{{1}提供的抽象}模块而不是使用TCP套接字,因此他们甚至不会像他们声称的那样从头开始做任何事情。

    如果问题是"如何从头开始实现静态文件服务器,作为学习练习"然后通过各种方式回答如何做到这一点应该发布 - 但即便如此,我们应该期望它们至少正确。此外,假设想要提供图像的人可能希望将来提供更多图像是不合理的,因此可以争辩说编写一个特定的自定义静态文件服务器,只能为一个具有硬编码路径的文件提供服务,有些短视。似乎很难想象任何搜索如何提供图像的答案的人都会满足于只提供单个图像的解决方案,而不是提供服务任何图像的通用解决方案。

    简而言之,问题是如何提供图像,答案就是使用适当的模块以安全,预先形成且可靠的方式 读取,在使用专业节点开发的最佳实践的同时,可维护且面向未来。但我同意,对这样一个答案的一个很好的补充就是展示了一种手动实现相同功能的方法,但遗憾的是,到目前为止,每次尝试这样做都失败了。这就是为什么我写了一些新的例子。

    在这个简短的介绍之后,以下是我在五个不同抽象层次上完成工作的五个例子。

    最低功能

    每个示例都提供http目录中的文件,并支持以下最小功能:

    • 大多数常见文件的MIME类型
    • 提供HTML,JS,CSS,纯文本和图像
    • public作为默认目录索引
    • 使用错误代码回复丢失的文件
    • 没有路径遍历漏洞
    • 阅读文件时没有竞争条件

    我测试了Node版本4,5,6和7上的每个版本。

    index.html

    此版本使用one correct answer模块的express.static内置中间件。

    此示例具有最多功能和最少量的代码。

    express.static

    var path = require('path'); var express = require('express'); var app = express(); var dir = path.join(__dirname, 'public'); app.use(express.static(dir)); app.listen(3000, function () { console.log('Listening on http://localhost:3000/'); });

    此版本使用express模块,但没有express中间件。服务静态文件使用流实现为单个路由处理程序。

    此示例具有简单的路径遍历对策,并支持一组有限的最常见MIME类型。

    express.static

    var path = require('path'); var express = require('express'); var app = express(); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; app.get('*', function (req, res) { var file = path.join(dir, req.path.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { return res.status(403).end('Forbidden'); } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.createReadStream(file); s.on('open', function () { res.set('Content-Type', type); s.pipe(res); }); s.on('error', function () { res.set('Content-Type', 'text/plain'); res.status(404).end('Not found'); }); }); app.listen(3000, function () { console.log('Listening on http://localhost:3000/'); });

    此版本使用express模块,该模块是低于connect的一级抽象。

    此示例具有与express版本类似的功能,但使用稍低杠杆的API。

    express

    var path = require('path'); var connect = require('connect'); var app = connect(); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; app.use(function (req, res) { var reqpath = req.url.toString().split('?')[0]; if (req.method !== 'GET') { res.statusCode = 501; res.setHeader('Content-Type', 'text/plain'); return res.end('Method not implemented'); } var file = path.join(dir, reqpath.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { res.statusCode = 403; res.setHeader('Content-Type', 'text/plain'); return res.end('Forbidden'); } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.createReadStream(file); s.on('open', function () { res.setHeader('Content-Type', type); s.pipe(res); }); s.on('error', function () { res.setHeader('Content-Type', 'text/plain'); res.statusCode = 404; res.end('Not found'); }); }); app.listen(3000, function () { console.log('Listening on http://localhost:3000/'); });

    此版本使用connect模块,该模块是节点中HTTP的最低级API。

    此示例具有与http版本类似的功能,但使用更低级别的API。

    connect

    var path = require('path'); var http = require('http'); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; var server = http.createServer(function (req, res) { var reqpath = req.url.toString().split('?')[0]; if (req.method !== 'GET') { res.statusCode = 501; res.setHeader('Content-Type', 'text/plain'); return res.end('Method not implemented'); } var file = path.join(dir, reqpath.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { res.statusCode = 403; res.setHeader('Content-Type', 'text/plain'); return res.end('Forbidden'); } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.createReadStream(file); s.on('open', function () { res.setHeader('Content-Type', type); s.pipe(res); }); s.on('error', function () { res.setHeader('Content-Type', 'text/plain'); res.statusCode = 404; res.end('Not found'); }); }); server.listen(3000, function () { console.log('Listening on http://localhost:3000/'); });

    此版本使用http模块,该模块是Node中TCP套接字的最低级API。

    此示例具有net版本的一些功能,但最小和不完整的HTTP协议已从头开始实施。由于它不支持分块编码,因此在发送响应之前将文件加载到内存中,然后才能知道大小,因为定位文件然后加载会引入竞争条件。

    http

    下载示例

    我在GitHub上发布了所有示例,并附有更多解释。

    var path = require('path'); var net = require('net'); var fs = require('fs'); var dir = path.join(__dirname, 'public'); var mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', svg: 'image/svg+xml', js: 'application/javascript' }; var server = net.createServer(function (con) { var input = ''; con.on('data', function (data) { input += data; if (input.match(/\n\r?\n\r?/)) { var line = input.split(/\n/)[0].split(' '); var method = line[0], url = line[1], pro = line[2]; var reqpath = url.toString().split('?')[0]; if (method !== 'GET') { var body = 'Method not implemented'; con.write('HTTP/1.1 501 Not Implemented\n'); con.write('Content-Type: text/plain\n'); con.write('Content-Length: '+body.length+'\n\n'); con.write(body); con.destroy(); return; } var file = path.join(dir, reqpath.replace(/\/$/, '/index.html')); if (file.indexOf(dir + path.sep) !== 0) { var body = 'Forbidden'; con.write('HTTP/1.1 403 Forbidden\n'); con.write('Content-Type: text/plain\n'); con.write('Content-Length: '+body.length+'\n\n'); con.write(body); con.destroy(); return; } var type = mime[path.extname(file).slice(1)] || 'text/plain'; var s = fs.readFile(file, function (err, data) { if (err) { var body = 'Not Found'; con.write('HTTP/1.1 404 Not Found\n'); con.write('Content-Type: text/plain\n'); con.write('Content-Length: '+body.length+'\n\n'); con.write(body); con.destroy(); } else { con.write('HTTP/1.1 200 OK\n'); con.write('Content-Type: '+type+'\n'); con.write('Content-Length: '+data.byteLength+'\n\n'); con.write(data); con.destroy(); } }); } }); }); server.listen(3000, function () { console.log('Listening on http://localhost:3000/'); }); express.staticexpressconnecthttp的示例:

    仅使用net的其他项目:

    测试

    测试结果可在Travis上获得:

    所有内容都在节点版本4,5,6和7上进行测试。

    另见

    其他相关答案:

答案 2 :(得分:60)

您应该使用express框架。

npm install express

var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(8080);

然后url localhost:8080 / images / logo.gif应该可以工作

答案 3 :(得分:13)

我喜欢使用Restify来提供REST服务。在我的例子中,我创建了一个REST服务来提供图像,然后如果图像源返回404/403,我想返回一个替代图像。这就是我想到的结合这里的一些东西:

function processRequest(req, res, next, url) {
    var httpOptions = {
        hostname: host,
        path: url,
        port: port,
        method: 'GET'
    };

    var reqGet = http.request(httpOptions, function (response) {
        var statusCode = response.statusCode;

        // Many images come back as 404/403 so check explicitly
        if (statusCode === 404 || statusCode === 403) {
            // Send default image if error
            var file = 'img/user.png';
            fs.stat(file, function (err, stat) {
                var img = fs.readFileSync(file);
                res.contentType = 'image/png';
                res.contentLength = stat.size;
                res.end(img, 'binary');
            });

        } else {
            var idx = 0;
            var len = parseInt(response.header("Content-Length"));
            var body = new Buffer(len);

            response.setEncoding('binary');

            response.on('data', function (chunk) {
                body.write(chunk, idx, "binary");
                idx += chunk.length;
            });

            response.on('end', function () {
                res.contentType = 'image/jpg';
                res.send(body);
            });

        }
    });

    reqGet.on('error', function (e) {
        // Send default image if error
        var file = 'img/user.png';
        fs.stat(file, function (err, stat) {
            var img = fs.readFileSync(file);
            res.contentType = 'image/png';
            res.contentLength = stat.size;
            res.end(img, 'binary');
        });
    });

    reqGet.end();

    return next();
}

答案 4 :(得分:12)

按要求提供Vanilla节点版本:

var http = require('http');
var url = require('url');
var path = require('path');
var fs = require('fs');

http.createServer(function(req, res) {
  // parse url
  var request = url.parse(req.url, true);
  var action = request.pathname;
  // disallow non get requests
  if (req.method !== 'GET') {
    res.writeHead(405, {'Content-Type': 'text/plain' });
    res.end('405 Method Not Allowed');
    return;
  }
  // routes
  if (action === '/') {
    res.writeHead(200, {'Content-Type': 'text/plain' });
    res.end('Hello World \n');
    return;
  }
  // static (note not safe, use a module for anything serious)
  var filePath = path.join(__dirname, action).split('%20').join(' ');
  fs.exists(filePath, function (exists) {
    if (!exists) {
       // 404 missing files
       res.writeHead(404, {'Content-Type': 'text/plain' });
       res.end('404 Not Found');
       return;
    }
    // set the content type
    var ext = path.extname(action);
    var contentType = 'text/plain';
    if (ext === '.gif') {
       contentType = 'image/gif'
    }
    res.writeHead(200, {'Content-Type': contentType });
    // stream the file
    fs.createReadStream(filePath, 'utf-8').pipe(res);
  });
}).listen(8080, '127.0.0.1');

答案 5 :(得分:12)

为时已晚但帮助了某人,我正在使用node version v7.9.0express version 4.15.0

如果您的目录结构是这样的:

your-project
   uploads
   package.json
   server.js

server.js代码:

var express         = require('express');
var app             = express();
app.use(express.static(__dirname + '/uploads'));// you can access image 
 //using this url: http://localhost:7000/abc.jpg
//make sure `abc.jpg` is present in `uploads` dir.

//Or you can change the directory for hiding real directory name:

`app.use('/images', express.static(__dirname+'/uploads/'));// you can access image using this url: http://localhost:7000/images/abc.jpg


app.listen(7000);

答案 6 :(得分:3)

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

http.createServer(function(req, res) {
  res.writeHead(200,{'content-type':'image/jpg'});
  fs.createReadStream('./image/demo.jpg').pipe(res);
}).listen(3000);
console.log('server running at 3000');

答案 7 :(得分:2)

您需要使用知道URL和静态文件的库。我建议使用Express。它具有设置路由的功能,以及静态文件服务模块。

答案 8 :(得分:2)

让我添加到上面的答案中来,优化图像和提供响应式图像可以显着缩短页面加载时间,因为90%以上的网络流量都是图像。您可能希望使用JS / Node模块(例如imagemin和相关插件)进行预处理图像,理想情况下是在使用Grunt或Gulp进行构建的过程中。

优化图像是指进行处理以找到理想的图像类型,然后选择最佳压缩以实现图像质量和文件大小之间的平衡。

提供自适应图像可转换为自动为每个图像创建多种尺寸和格式,并在HTML中使用<?php $args = array( 'posts_per_page' => 1, 'post_type' => 'attachment', 'post_status' => 'any', 'orderby' => 'rand', 'meta_key' => 'image_category', 'meta_value' => 'bottom', ); $the_query = new WP_Query( $args ); ?> <?php if ( $the_query->have_posts() ) : ?> <?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?> <section id="bottom"> <div class="bottom-image"> <?php echo wp_get_attachment_image( get_the_ID(), 'full'); ?> </div> </section> <?php endwhile; ?> <?php wp_reset_postdata(); ?> <?php endif; ?> 可为您提供最佳的图像集(即理想的格式和尺寸) ,因此是每个浏览器的最佳文件大小)。

图像处理自动化是指在构建过程中将其整合一次,并进一步展示优化的图像,所需的额外时间最少。

一般来说,responsive imagesminificationimagemin节点模块和 using srcset都有不错的读物。

答案 9 :(得分:1)

此方法对我有用,它不是动态的,但很直接:

const fs      = require('fs');
const express = require('express');
const app     = express();

app.get( '/logo.gif', function( req, res ) {

  fs.readFile( 'logo.gif', function( err, data ) {

    if ( err ) {

      console.log( err );
      return;
    }

    res.write( data );
    return res.end();
  });

});

app.listen( 80 );

答案 10 :(得分:0)

这可能有点题外话,因为您正在询问通过Node.js专门提供静态文件的问题(其中fs.createReadStream('./image/demo.jpg').pipe(res)实际上是一个好主意),但是在生产中,您可能希望拥有Node应用程序处理否则无法解决的任务,并将静态服务卸载到例如Nginx。这意味着应用程序内的编码更少,效率更高,这是因为反向代理在设计上是理想的选择。

答案 11 :(得分:0)

//This method involves directly integrating HTML Code in the res.write
//first time posting to stack ...pls be kind

const express = require('express');
const app = express();
const https = require('https');

app.get("/",function(res,res){
    res.write("<img src="+image url / src +">");
    res.send();
});

app.listen(3000, function(req, res) {
  console.log("the server is onnnn");
});