node.js - كيفية تقديم صورة باستخدام nodejs



(6)

لدي شعار مقيم في الجمهور / 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 فمن الواضح أنني لا أحصل على الشعار.

ما هي التغييرات التي أحتاجها لتقديم صورة.


تحديث 2016

أمثلة مع Express و بدون Express تعمل بالفعل

هذا السؤال هو أكثر من 5 سنوات ولكن كل إجابة لها بعض المشاكل .

TL، DR

مرِّر لأسفل للحصول على أمثلة لتقديم صورة تتضمن:

  1. express.static
  2. express
  3. connect
  4. http
  5. net

جميع الأمثلة موجودة أيضًا على GitHub: https://github.com/rsp/node-static-http-servers

نتائج الاختبار متاحة على ترافيس: https://travis-ci.org/rsp/node-static-http-servers

المقدمة

بعد أكثر من 5 سنوات منذ طرح هذا السؤال لا يوجد سوى إجابة واحدة صحيحة من قبل generalhenry ولكن على الرغم من أن هذا الجواب لا توجد لديه مشاكل مع رمز ، يبدو أن لديها بعض المشاكل مع الاستقبال . وقد تم التعليق على أنه "لا يفسر الكثير عن كيفية الاعتماد على شخص آخر لإنجاز المهمة" ، وحقيقة عدد الأشخاص الذين صوّتوا هذا التعليق يظهر بوضوح أن الكثير من الأشياء تحتاج إلى توضيح.

أولاً ، لا تُعد الإجابة الجيدة على "كيفية تقديم الصور باستخدام Node.js" تنفيذ خادم ملفات ثابت من البداية وفعله بشكل سيئ. الإجابة الجيدة هي استخدام وحدة نمطية مثل Express تقوم بالمهمة بشكل صحيح .

الإجابة على التعليقات التي تفيد بأن استخدام Express لا "يفسر الكثير عن كيفية الاعتماد على شخص آخر لإنجاز المهمة" ، تجدر الإشارة إلى أن استخدام وحدة http يعتمد بالفعل على شخص آخر لإنجاز المهمة. إذا لم يرغب شخص ما في الاعتماد على أي شخص لإنجاز المهمة ، فيجب استخدام مآخذ بروتوكول TCP على الأقل بدلاً من ذلك - وهو ما أفعله في أحد الأمثلة أدناه.

مشكلة أكثر خطورة هي أن جميع الإجابات هنا التي تستخدم وحدة http مكسورة . إنهم يقدمون شروطًا للسباق ، وحل مسار غير آمن يؤدي إلى التعرض لخطر الانحدار ، ويعرقل الإدخال / الإخراج الذي سيخفق تمامًا في تقديم أي طلبات متزامنة على الإطلاق ومشاكل أخرى دقيقة - يتم كسرها تمامًا كأمثلة لما يطرحه السؤال ، و ومع ذلك يستخدمون بالفعل التجريد الذي يتم توفيره من قبل وحدة http بدلا من استخدام مآخذ TCP حتى لا يفعلوا كل شيء من الصفر كما يدعون.

إذا كان السؤال هو "كيفية تنفيذ خادم الملفات الثابت من البداية ، كتمرين تعليمي" ، فيجب بكل الوسائل الإجابة عن كيفية القيام بذلك - ولكن حتى في هذه الحالة يجب أن نتوقع أن تكون صحيحة على الأقل. أيضا ، ليس من غير المعقول أن نفترض أن شخصًا ما يريد عرض صورة قد يرغب في تقديم المزيد من الصور في المستقبل ، لذا يمكن للمرء أن يجادل بأن كتابة خادم ملفات ثابت مخصص محدد يمكن أن يخدم ملفًا واحدًا فقط مع مسار مشفر قصيرة النظر إلى حد ما. يبدو من الصعب أن نتخيل أن أي شخص يبحث عن إجابة حول كيفية عرض صورة سيكون مضمونًا بحل يخدم صورة واحدة فقط بدلاً من حل عام لخدمة أي صورة.

باختصار ، السؤال هو كيفية تقديم صورة وإجابة على ذلك هو استخدام وحدة نمطية مناسبة للقيام بذلك بطريقة آمنة وموثوقة وموثوقة وقابلة للقراءة وموثوقة ومستقبلية مع استخدام أفضل الممارسات للعقدة المهنية تطوير. ولكنني أوافق على أن إضافة رائعة إلى مثل هذه الإجابة ستعرض طريقة لتنفيذ الوظيفة نفسها يدويًا ، ولكن للأسف ، كل محاولة لفعل ذلك قد فشلت حتى الآن. ولهذا السبب كتبت بعض الأمثلة الجديدة.

بعد هذه المقدمة القصيرة ، إليك الأمثلة الخمسة التي أنجزها في 5 مستويات مختلفة من التجريد.

الحد الأدنى من الوظائف

كل مثال يخدم ملفات من الدليل public ويدعم وظيفة minumum من:

  • أنواع MIME لأكثر الملفات شيوعًا
  • يقدم HTML و JS و CSS والنص العادي والصور
  • يخدم index.html كمؤشر دليل افتراضي
  • يستجيب مع رموز الخطأ للملفات المفقودة
  • لا ثغرات اجتياز المسار
  • لا شروط العرق أثناء قراءة الملفات

اختبرت كل إصدار على إصدارات Node 4 و 5 و 6 و 7.

express.static

يستخدم هذا الإصدار الوسيطة المدمجة express.static من وحدة express .

يحتوي هذا المثال على معظم الوظائف وأقل كمية من التعليمات البرمجية.

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 ولكن دون الوسيطة express.static . يتم تنفيذ خدمة الملفات الثابتة كمعالج توجيه فردي باستخدام مجموعات البث.

يحتوي هذا المثال على إجراءات مضادة بسيطة تتبع المسار ويدعم مجموعة محدودة من أكثر أنواع MIME شيوعًا.

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

connect

يستخدم هذا الإصدار وحدة connect التي هي مستوى تجريد واحد أقل من express .

يحتوي هذا المثال على وظائف مشابهة للإصدار express ولكن باستخدام واجهات برمجة التطبيقات (APIs) السفلية ذات الأذرع السفلية قليلاً.

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

http

يستخدم هذا الإصدار وحدة http التي هي واجهة برمجة التطبيقات ذات المستوى الأدنى لـ HTTP في العقدة.

يحتوي هذا المثال على وظائف مشابهة لإصدار 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/');
});

net

يستخدم هذا الإصدار الوحدة النمطية net وهو واجهة برمجة التطبيقات ذات المستوى الأدنى لمآخذ توصيل TCP في عقدة.

يحتوي هذا المثال على بعض وظائف إصدار http ولكن تم تنفيذ بروتوكول HTTP الخاص بالحد الأدنى وغير الكامل من البداية. نظرًا لأنه لا يدعم الترميز المطبق ، فإنه يحمّل الملفات إلى الذاكرة قبل تقديمها لمعرفة الحجم قبل إرسال استجابة لأن statting الملفات ثم التحميل سيؤدي إلى ظهور حالة سباق.

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

قم بتنزيل الأمثلة

لقد نشرت كل الأمثلة على GitHub مع مزيد من الشرح.

أمثلة مع express.static و express و connect و http و net :

مشروع آخر باستخدام express.static فقط:

اختبارات

نتائج الاختبار متاحة على ترافيس:

يتم اختبار كل شيء على إصدارات Node 4 و 5 و 6 و 7.

أنظر أيضا

الإجابات الأخرى ذات الصلة:


أتفق مع الملصقات الأخرى التي في النهاية ، يجب عليك استخدام إطار عمل ، مثل Express ... ولكن أولاً يجب أن تفهم أيضًا كيفية القيام بشيء أساسي مثل هذا بدون مكتبة ، لكي تفهم حقاً ما هي ملخصات المكتبة بالنسبة لك .. الخطوات هي

  1. تحليل طلب HTTP الوارد ، لمعرفة المسار الذي يطلبه المستخدم
  2. أضف مسارًا في بيان شرطي للملقم للاستجابة له
  3. إذا كانت الصورة مطلوبة ، فاقرأ ملف الصورة من القرص.
  4. عرض نوع محتوى الصورة في رأس الصفحة
  5. خدمة محتويات الصورة في الجسم

سيبدو الرمز شيئًا مثل هذا (لم يتم اختباره)

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

أولا ، تحتاج إلى تثبيت حزمة صريحة من قبل npm . يمكنك تثبيته باستخدام npm i express .

بمجرد تثبيت الوحدة النمطية السريعة ، حدد التعليمة البرمجية التالية في ملفك:

const express = require('express'); const app = express(); app.use(express.static('public/images'));


بعد فوات الأوان ، ولكن يساعد شخص ما ، وأنا باستخدام node version v7.9.0 وإصدار express 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);

نسخة عقدة الفانيلا كما هو مطلوب:

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

يجب عليك استخدام الإطار express .

npm install express

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

ثم يجب أن تعمل 8080 / images / logo.gif





node.js