2015-11-20 3 views
1

У меня проблема с отображением простого изображения на веб-странице. У меня есть узел для API и веб-сервер узла для страниц просмотра. Код работал очень хорошо, но мне нужно добавить своего рода межсетевой шлюз (который будет обрабатывать аутентификацию в будущем), и он сломал код.Node REST API Проблема рендеринга изображений

Я использую экспресс и gridfs для хранения и извлечения файлов mongo.

Вот код

HTML/Угловое страница

<img id="image" ng-src="http:localhost:3000/api/files/images/{{data.image}}" alt="" /> 

Шлюз (узел)

var request = require('request'); 

//settings - retrive the url of the api backend micro-service 
var url = require('./configApiGw').url_service_api_contents; 

//api to retrive a file stored in mongo using gridfs 
app.get('/api/files/images/:id', function(req, res, next){ 
    var uri = url+'/api/files/images/:'+req.params.id; 
    request({ 
     uri: uri, 
     method: "GET", 
     timeout: 100000, 
     followRedirect: true, 
     maxRedirects: 10 
    }, function(error, response, body) {  
      res.send(response.body); 
    }); 
}); 

Backend API

app.get('/api/files/images/:id', function(req, res, next){ 
    //call function to read the file using gridfs. call back function 
    readFile(req, res, function(file){ 
     console.log('success'); 
    }); 
}); 

function readFile(req,res,callback){ 
    var fileId = req.params.id; 

    //delete the ':' that is added by the gateway 
    if(fileId.charAt(0) === ':'){ 
    fileId = fileId.slice(1); 
    } 

    // streaming from gridfs 
    var rstream = gfs.createReadStream({filename: fileId}); 
    var bufs = []; 

    rstream.on('data', function (chunk) { 
    bufs.push(chunk); 
    }); 

    // done reading the file 
    rstream.on('end', function() { 
    var fbuf = Buffer.concat(bufs); 
    var file = (fbuf.toString('base64')); 
    callback(file); 
    }); 

    //error handling, e.g. file does not exist 
    rstream.on('error', function (err) { 
    console.log('An error occurred!', err); 
    console.log(err); 
    res.send(500,err); 
    }); 

    rstream.pipe(res); 
} 

Изображение не отображается, но я получаю ответ 200 OK как от бэкэнд API, так и от шлюза. Когда я смотрю на детали изображения в браузере, я вижу следующие данные: - Расположение: http://localhost:3000/api/files/images/file.jpeg - Тип: текст/html - Размер: Unknown (не кэшированные)

Что я делаю неправильно? большое спасибо.

Редактировать с Alexandr входы

шлюза (Node) V2

var request = require('request'); 

//settings - retrive the url of the api backend micro-service 
var url = require('./configApiGw').url_service_api_contents; 

app.get('/api/files/images/:id', function(req, res, next){ 
var uri = url+'/api/files/images/:'+req.params.id; 
request({ 
    uri: uri, 
    method: "GET", 
    timeout: 100000, 
    followRedirect: true, 
    maxRedirects: 10 
}, function(error, response, body) { 
     res.set('Content-Type', response.headers['content-type']); 
     res.send(response.body); 
    }); 
}); 

Backend API V2

//api to retrive a file stored in mongo using gridfs 
app.get('/api/files/images/:id', function(req, res, next){ 
    //call function to read the file using gridfs. call back function 
    db.readFile(req, res, function(file){ 
     //res.send(file); 
     console.log("success"); 
    }); 
}); 

readFile = function(req,res,callback){ 
    var fileId = req.params.id; 

    //delete the ':' that is added by the gateway 
    if(fileId.charAt(0) === ':'){ 
    fileId = fileId.slice(1); 
    } 

    //setHeaders content type for the file 
    setHeaders(fileId, function(contentType){ 
    res.writeHead('200',{'Content-Type':contentType}); 

    // streaming from gridfs 
    var rstream = gfs.createReadStream({filename: fileId}); 
    var bufs = []; 

    rstream.on('data', function (chunk) { 
     bufs.push(chunk); 
    }); 

    // done reading the file 
    rstream.on('end', function() { 
     var fbuf = Buffer.concat(bufs); 
     var file = (fbuf.toString('binary')); 

     callback(file); 
    }); 

    //error handling, e.g. file does not exist 
    rstream.on('error', function (err) { 
     console.log('An error occurred!', err); 
    console.log(err); 
     res.send(500,err); 
    }); 

    rstream.pipe(res); 

    }); 
}; 

function setHeaders(fileId, callback){ 
    var ext = path.extname(fileId); 
    var contentType = 'text/html'; 
    if (ext === '.gif') { 
     contentType = 'image/gif'; 
    } 
    if (ext === '.jpeg') { 
     contentType = 'image/jepg'; 
    } 
    if (ext === '.png') { 
     contentType = 'image/png'; 
    } 
    if (ext === '.jpg') { 
     contentType = 'image/jpg'; 
    } 
    callback(contentType); 
} 

В результате до сих пор не хорошо: изображение не отображается. НО, теперь тип контента правильно установлен.

добавив здесь заголовки (Почтальон):

Access-Control-Allow-Headers → Origin, X-Requested-With, Content-Type, Accept 
Access-Control-Allow-Origin → * 
Connection → keep-alive 
Content-Length → 82360 
Content-Type → image/jepg; charset=utf-8 
Date → Fri, 20 Nov 2015 10:15:55 GMT 
ETag → W/"141b8-Ox5qDdvc3kZTunf0uqMVQg" 
X-Powered-By → Express 
+2

Просто вопрос о пути ворот. Поскольку вы используете AngularJs, почему вы не можете создать файл controller.js? и использовать это как шлюз. В основном создайте контроллер angularJS и создайте очень простой HTTP-вызов Javascript для извлечения ваших данных. Этот HTTP-вызов будет идти по маршруту в вашем Node API. – Skywalker

ответ

1

UPDATE

Попробуйте установить encoding свойство null в объекте запроса:

app.get('/api/files/images/:id', function(req, res, next){ 
var uri = url+'/api/files/images/:'+req.params.id; 
request({ 
    uri: uri, 
    method: "GET", 
    timeout: 100000, 
    followRedirect: true, 
    encoding: null, 
    maxRedirects: 10 
}, function(error, response, body) { 
     res.set('Content-Type', response.headers['content-type']); 
     res.send(response.body); 
    }); 
}); 

Кроме того, набор изображений заголовки Content-Type для ваших ответов:

app.get('/api/files/images/:id', function(req, res, next){ 
    //call function to read the file using gridfs. call back function 
    readFile(req, res, function(file){ 
     res.set('Content-Type', 'image/jpeg'); //it can different, depends on the image 
     res.send(file); 
    }); 
}); 

шлюз :

app.get('/api/files/images/:id', function(req, res, next){ 
var uri = url+'/api/files/images/:'+req.params.id; 
request({ 
    uri: uri, 
    method: "GET", 
    timeout: 100000, 
    followRedirect: true, 
    maxRedirects: 10 
}, function(error, response, body) { 
     res.set('Content-Type', response.headers['content-type']); 
     res.send(response.body); 
    }); 
}); 
+0

Если я устанавливаю заголовки точно так же, как в вашем примере, я получаю сообщение о том, что я не могу установить заголовки после отправки ответа. Поэтому я переместил тип содержимого res.set перед потоковой передачей файла из базы данных. Это лучше, потому что теперь у меня есть правильный тип контента. Но на странице все еще ничего не отображается. Если я добавлю res.send (файл) в обратный вызов readFile, я получаю сообщение об ошибке «не может отправлять заголовки после их отправки». Поэтому я задаюсь вопросом, не связана ли моя проблема с моей функцией обратного вызова. – edevregille

+0

И каков был результат? –

+0

интересно отметить, что он работает с файлом HTML: я правильно отобразил файл. Но не работает для изображения. Я не понимаю, почему. Может быть, кодировка? – edevregille

0

Да, я уже использую контроллер для всех остальных компонентов страницы, но я называю непосредственно со страницы HTML в API для retrive изображения. Вы правы, я могу это изменить. Шлюз здесь также потому, что у меня есть несколько компонентов API (архитектура микросервиса), и поэтому шлюз - отличный способ абстрагировать все эти различные компоненты для веб-клиента. Я предпочел бы, чтобы шлюзы следовали шаблону архитектуры микросервисов.

Смежные вопросы