I am trying to pipe images from an Amazon S3 server through my node server while adding a custom header to the response.
Right now, however, the server will respond with a plain "Document" that will download to my computer with no file extension declared. The "Document" still contains the desired image data, but how can I make it clear that this is a PNG that can be viewed in my browser?
Here's my current code:
app.get('/skin', function (req, res) {
res.writeHead(200, {'Content-Type': 'image/png', 'access-control-allow-origin': '*'});
http.get("http://s3.amazonaws.com/MinecraftSkins/clone1018.png").pipe(res);
});
You might want to use http.request in order to make nice proxying and resource loading with duplicating headers.
Here is example in express that will listen on port 8080, and will make request to specific server with actually url that you request from /skin/* route:
var http = require('http'),
express = require('express'),
app = express();
app.get('/skin/*', function(req, res, next) {
var request = http.request({
hostname: 's3.amazonaws.com',
port: 80,
path: '/' + req.params[0],
method: req.method
}, function(response) {
if (response.statusCode == 200) {
res.writeHead(response.statusCode, response.headers);
response.pipe(res);
} else {
res.writeHead(response.statusCode);
res.end();
}
});
request.on('error', function(e) {
console.log('something went wrong');
console.log(e);
})
request.end();
});
app.listen(8080);
In order to test it out, run it on your machine, and then go to: http://localhost:8080/skin/nyc1940/qn01_GEO.png
It will load that image proxying from Amazon, and returning its headers as well. You might customize headers as well, in order to prevent XML being sent from S3 (when file does not exist).
You dont need to set any headers as they are proxied from s3.amazon and it does reliably set right headers for you.
Nor access-control-allow-origin as you will need it only in case with AJAX request to resource from another domain name. But anyway feel free to modify response.headers before sending out. It is simple object (console.log it for tests).
Related
I am trying to setup a very simple nodeJS HTTP server. When I call it from the browser, like this http://localhost:8081, it works fine, but when I call is using a JS fetch() method, I get a 404 error:
GET http://localhost/:8081?q=hi
JS:
fetch(":8081/?q=hi")
NODE JS:
const requestListener = function (req, res) {
res.writeHead(200);
res.end('Hello, World!');
}
const server = http.createServer(requestListener);
server.listen(8081);
Every thing is fine, you just need to enable cors that's it, use the below code
const http = require('http')
const requestListener = function (req, res) {
const headers = {
'Access-Control-Allow-Origin': '*', /* #dev First, read about security */
'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',
'Access-Control-Max-Age': 2592000, // 30 days
/** add other headers as per requirement */
};
res.writeHead(200, headers);
res.end(JSON.stringify({"key":"value"}));
}
const server = http.createServer(requestListener);
server.listen(8081);
If you are running both frontend and backend code on the same server then you don’t have to use complete url while if you are running fronted and backed on different server you need to enable cors and use complete url.
When you're calling your local server through JS fetch, you don't need to add the port number you can call it like below:
fetch('/?q=hi')
the URL handed to fetch function looks wronge, it would work if you adjust it to:
fetch('http://localhost:8081/?q=hi');
// or
fetch('/?q=hi');
it should work just fine,
and ensure that you enable the cors if you need to works from any domain
I'm doing a project with vue + nativescript
the function app.get is not triggerd when I'm calling it from the vue project
this call :
const urlChannels = 'http://localhost:3001/sources';
axios.get(urlChannels)
.then(response => {
store.commit('setTasks', {
channels: response.data,
});
})
}
returns :"data":"","status":null,"statusText":"" as if the server is off,(the call itself is valid it works with other apis)
but simple test with angularjs on the browser returns the valid needed data
this is my nodejs :
app.get('/sources', function (req, res) {
res.set({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET'
});
res.writeHead(200,{'Content-Type':'application/json'})
let data = getNews.getSources()
res.send(JSON.stringify(data));
//res.json(data); also tried this same resualt
})
res.end() is intended for ending the response without data (see https://expressjs.com/en/api.html).
If you want to return json, the easiest way is to use res.json():
app.get('/sources', function (req, res) {
res.set({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET'
});
let data = getNews.getSources()
res.json(data);
});
I found the problem, it's a security thing with ios, they don't allow http calls, only https (I run the project on an ios emulator)
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection
We have a Node/Restify app and I'm having a problem with this route (some code has been omitted, so please ignore missing identifiers):
server.post('/report', requireAuth, function (req, res, next) {
generateReport(err, result, extension, contentType) {
// Filename for the report
var filename = 'Report_' + moment().format('YYYY-MM-DD_HH:mm:ss')
// Output the result directly with a lower-level APIs
res.writeHead(200, {
'Content-Length': Buffer.byteLength(result),
'Content-Type': contentType,
'Content-Disposition': 'attachment;filename='+filename+'.'+extension
})
res.write(result, 'utf8')
res.end()
console.log('ended')
return next()
}
})
The problem is that, after sending the output, the connection with the client is not closed, even if I call res.end()! (res is just a wrapper around the standard HTTP ServerResponse module).Commenting out return next() doesn't make any difference.
I can see on the console 'ended' and I know the content is sent to the client because if I force the termination of the connection (by simply terminating the Node process), the client has all the output.
What am I doing wrong?
EDIT
Removing the Content-Length header, instead, makes it work. Why is that? (The advice to use that header is part of the documentation)
EDIT2
The value of Buffer.byteLength(result) is 4478 bytes, but the data downloaded by the client (Postman) is 4110, and that's likely why the connection is not being closed (the client is expecting to receive more data). How is that possible?
I'm assembling my first AngularJS app. My controller is making a $http.get() call. The url it's using is correct, but it ends up calling the "error" method with a 404. This is even more confusing when I see the URL being requested in Firebug, and it reports a 200.
I don't think I need to show the html for this. I can't imagine how that could be relevant.
Here's my somewhat elided javascript:
var diagapp = angular.module("DiagApp", ['ui.bootstrap', 'ngResource']);
diagapp.controller("DiagCtrl", ['$scope', '$interval', '$http', function($scope, $interval, $http) {
$http({method:'GET',url:'http://<hostportandpath>/service/diagnostics/datasourceStatus.json'})
.success(function (data, status, headers, config) {
console.log(data);
})
.error(function (data, status, headers, config) {
console.log(data);
});
}]);
I've tried setting a breakpoint at the "$http" line, and then copying and pasting the URL referenced on that line into another browser tab, and it shows me the correct json returned by that service. I then continue from the breakpoint, and it hits the breakpoint in the "error" method, and the status says 404.
What could I be doing wrong?
Update:
I've modified this so that the service call is only relative, so it doesn't violate the CDP.
I also set up a "node express" web server running at the root of my webapp, so it will serve requests for files in the webapp, but any calls to the REST service are 302-redirected to the service on another domain.
When I debug this in Firebug, I see it get the 302, and then I see it get the 200, so it obviously followed the redirect. However, it then hits the breakpoint in the "error" method, still saying it got a 404. In other words, I get the exact same result. I'm befuddled.
Update:
Here is my slightly elided "express server" configuration:
var express = require('express');
var app = express();
app.use("/", express.static(__dirname));
app.use(app.router);
app.get('/FooService/*', function(req, res) {
res.redirect(302, 'http://<hostname>' + req.path);
});
app.listen(8000);
I think you're getting an error because you're making a request to a different domain violating the Same Origin Policy (http://en.wikipedia.org/wiki/Same-origin_policy). Instead you should make a request to a server on you own domain and have that server provide the data you need (possibly by cacheing it from the other domain). Or you can use JSON-P and have the other domain your calling call a method on your client side.
Update
So to create the express server we first use the http library to make a request to get the json data we want and we store the response in the variable data. Then we setup our webserver just like you did except instead of responding with a redirect we respond with the data itself.
var express = require('express');
var http = require("http");
var app = express();
var data;
// Make the request to buffer the data
var options = {
host: 'somesite.com',
port: 1337,
path: '/some/path',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
var req = http.request(options, function(res)
{
var output = '';
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', function() {
data = JSON.parse(output);
});
});
req.on('error', function(err) {
//res.send('error: ' + err.message);
});
req.end();
// Start the webserver to respond with the data
app.use("/", express.static(__dirname));
app.use(app.router);
app.get('/FooService/*', function(req, res) {
response.writeHead(200, { 'Content-Type': 'application/json'});
response.end(data);
});
app.listen(8000);
Note I haven't been able to test this all yet so you may need to make some adjustments, but I have done very similar things with Node, Express and Angular and I'm sure this type of thing will work. You may want to adjust how often the data is cached on your server by putting the request in a setTimeout or making the request on demand in the app.get method (but that would be slower). You can read more about http.request() here: http://nodejs.org/api/http.html#http_http_request_options_callback
This is an annoying problem, and I don't suppose that it's only IE that has this problem. Basically I have a Node.js server, from which I am making cross-domain calls to get some JSON data for display.
This needs to be a JSONP call and I give a callback in the URL. What I am not sure is, how to do this?
So the website (domainA.com) has an HTML page with a JS script like this (all works fine in Firefox 3):
<script type="text/javascript">
var jsonName = 'ABC'
var url = 'http://domainB.com:8080/stream/aires/' //The JSON data to get
jQuery.getJSON(url+jsonName, function(json){
// parse the JSON data
var data = [], header, comment = /^#/, x;
jQuery.each(json.RESULT.ROWS,function(i,tweet){ ..... }
}
......
</script>
Now my Node.js server is very simple (I'm using express):
var app = require('express').createServer();
var express = require('express');
app.listen(3000);
app.get('/stream/aires/:id', function(req, res){
request('http://'+options.host+':'+options.port+options.path, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body); // Print the google web page.
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true'
});
res.end(JSON.stringify(JSON.parse(body)));
}
})
});
How can I change these two so they will work with cross-domain GET in IE? I have been searching the internet and there seem to be a few different things like jQuery.support.cors = true; which does not work. There also seem to be a lot of lengthy workarounds.
There is no real 'ideal' design pattern which I have been able to find for this type of thing.
Seeing as I have control over both the web page and the cross domain web service I'm sending to what is the best change to make to ensure compatability across all IE versions along with FireFox, Opera, Chrome etc?
Cheers!
Say we have two servers, myServer.com and crossDomainServer.com, both of which we control.
Assuming we want a client of myServer.com to pull some data from crossDomainServer.com, first that client needs to make a JSONP request to crossDomainServer.com:
// client-side JS from myServer.com
// script tag gets around cross-domain security issues
var script = document.createElement('script');
script.src = 'http://crossDomainServer.com/getJSONPResponse';
document.body.appendChild(script); // triggers a GET request
On the cross-domain server we need to handle this GET request:
// in the express app for crossDomainServer.com
app.get('/getJSONPResponse', function(req, res) {
res.writeHead(200, {'Content-Type': 'application/javascript'});
res.end("__parseJSONPResponse(" + JSON.stringify('some data') + ");");
});
Then in our client-side JS we need a global function to parse the JSONP response:
// gets called when cross-domain server responds
function __parseJSONPResponse(data) {
// now you have access to your data
}
Works well across a wide variety of browsers, IE 6 included.
The following code shows how to handle the GET request (using express) and how to wrap the JSON response using the callback given:
app.get('/foo', function(req, res){
res.header('Content-Type', 'application/json');
res.header('Charset', 'utf-8')
res.send(req.query.callback + '({"something": "rather", "more": "pork", "tua": "tara"});');
});