I know this has been gone over before but I've spent hours on this and can't seem to figure out how to post data to a node.js server... I've started the project using cloud9 and node.js so I know I have a good install and that I'm starting with a working site.
In swift I'm sending a post request like
func post (){
let url = URL(string: "https://the-game-stevens-apps.c9users.io/index.html/")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Accept")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
let postString = "name=henry&message=HelloWorld"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
}
Then in my server.js file I have
var router = express();
router.use(express.urlencoded());
router.post('/index.html', function(req, res) {
var obj = {name:req.body.name,text:req.body.message};
});
I have plenty of experience with javascript but I'm a noob when it comes to node.js and have just been poking around with it, any help is really appreciated
The only part I can correct in your node.js code is
To get router you need to call express.Router();
const express = require('express');
const router = express.Router();
router.use((req,res,next) => {
console.log("/" + req.method, "host"+ req.host, "Params" + req.params);
next();
});
router.post('/index.html', (req, res) => {
const obj = {name:req.body.name,text:req.body.message};
//insert obj into database
});
Related
I am building out an API using Node for the first time but a little stuck on something.
I have the following files:
My routes, routes/index.js:
const express = require('express');
const router = express.Router();
const transactionsController = require('../controllers/transactionsController');
const ordersController = require('../controllers/ordersController');
const ordersCountController = require('../controllers/ordersCountController');
router.get('/transactions', transactionsController);
router.get('/orders', ordersController);
router.get('/orders_count', ordersCountController);
module.exports = router;
My controllers, controllers/ordersCountController.js:
const ordersCountService = require('../services/ordersCountService');
const ordersCountController = async () => {
try {
const data = await ordersCountService();
console.log(data);
return data;
} catch(err) {
console.log(err);
}
};
module.exports = ordersCountController;
My service to fetch from an external API, services/ordersCountService.js:
const fetch = require('node-fetch');
const ordersCountService = async () => {
const URL = ....;
const settings = { method: 'Get'};
const res = await fetch(URL, settings);
if (!res.ok) throw new Error('Unable to retrieve data');
return await res.json();
}
module.exports = ordersCountService;
How can I pass the JSON through to the browser?
I have been trying a few things - you'll notice the return data; - but I can't figure out how to return the JSON so that it's displayed in the browser when someone visits ourdomain.com/api/orders_count.
Any suggestions as to what I am doing wrong here? I am still new to JS so sorry if I am missing something completely obvious here.
Thank you all for your time. If there is anything I can add for clarity, please don't hesitate to ask.
In your controller, ordersCountService should have 2 parameters: req and res:
The req object represents the HTTP request and has properties for the request query string, parameters, body, and HTTP headers.
The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
In this case, your controller should be:
const ordersCountController = async (req, res) => {
try {
const data = await ordersCountService();
console.log(data);
res.json({data})
} catch(err) {
console.log(err);
}
};
Save it, and open the express server, and type the route url in the browser, you would see the json format.
You could find more information about Express in this article.
Express Explained with Examples - Installation, Routing, Middleware, and More
I'm trying to write a header of an MD5 hash token using crypto then return it back as a response. For some reason, it isn't actually running synchronously. I know JS is an asynchronous language, and that's really the only part I'm struggling with right now. Any help would be appreciated.
This is what I have so far:
const crypto = require('crypto');
const bodyParser = require('body-parser');
const formidable = require('formidable');
const async = require('async')
app.post('/pushurl/auth', (req, res) =>
var data = req.body.form1data1 + '§' + req.body.form1data2
async.waterfall([
function(callback) {
var token = crypto.createHash('md5').update(data).digest("hex");
callback(null, token);
},
function(token, callback) {
res.writeHead(301,
{Location: '/dashboard?token=' + token}
);
callback(null)
},
function(callback) {
res.end();
callback(null)
}
]);
}
});
Output:
Uncaught Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
<node_internals>/internal/errors.js:256
No debugger available, can not send 'variables'
Process exited with code 1
JavaScript is an asynchronous language, yes, but it can also do synchronous tasks very well. In your case, you don't need to do any async expect if you're dealing with promises.
If you write your code like in the example below it will just execute from top to bottom.
But the error (probably) occurred because you forgot to add an opening curly brace to your app.post callback, which results in the data var being immediately returned because of an implied return statement () => (implied), () => {} (explicit).
const crypto = require('crypto');
const bodyParser = require('body-parser');
const formidable = require('formidable');
app.post('/pushurl/auth', (req, res) => {
const data = req.body.form1data1 + '§' + req.body.form1data2;
const token = crypto.createHash('md5').update(data).digest("hex");
res.writeHead(301, {
Location: '/dashboard?token=' + token
});
res.end();
});
I have an http-proxy to proxy any website and inject some custom JS file before to serve the HTML back to the client. Whenever I try to access the proxied website, it will hang up or the browser seems to load indeterminately. But when I check the HTML source, I successfully managed to inject my custom JavaScript file. Here is the code:
const cheerio = require('cheerio');
const http = require('http');
const httpProxy = require('http-proxy');
const { ungzip } = require('node-gzip');
_initProxy(host: string) {
let proxy = httpProxy.createProxyServer({});
let option = {
target: host,
selfHandleResponse: true
};
proxy.on('proxyRes', function (proxyRes, req, res) {
let body = [];
proxyRes.on('data', function (chunk) {
body.push(chunk);
});
proxyRes.on('end', async function () {
let buffer = Buffer.concat(body);
if (proxyRes.headers['content-encoding'] === 'gzip') {
try {
let $ = null;
const decompressed = await ungzip(buffer);
const scriptTag = '<script src="my-customjs.js"></script>';
$ = await cheerio.load(decompressed.toString());
await $('body').append(scriptTag);
res.end($.html());
} catch (e) {
console.log(e);
}
}
});
});
let server = http.createServer(function (req, res) {
proxy.web(req, res, option, function (e) {
console.log(e);
});
});
console.log("listening on port 5051");
server.listen(5051);
}
Can someone please tell me if I am doing anything wrong, it looks like node-http-proxy is dying a lot and can't rely much on it since the proxy can work sometimes and die at the next run, depending on how many times I ran the server.
Your code looked fine so I was curious and tried it.
Although you do log a few errors, you don't handle several cases:
The server returns a body with no response (cheerio will generate an empty HTML body when this happens)
The server returns a response that is not gzipped (your code will silently discard the response)
I made a few modifications to your code.
Change initial options
let proxy = httpProxy.createProxyServer({
secure: false,
changeOrigin: true
});
Don't verify TLS certificates secure: false
Send the correct Host header changeOrigin: true
Remove the if statement and replace it with a ternary
const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
const decompressed = isCompressed ? await ungzip(buffer) : buffer;
You can also remove the 2 await on cheerio, Cheerio is not async and doesn't return an awaitable.
Final code
Here's the final code, which works. You mentioned that "it looks like node-http-proxy is dying a lot [...] depending on how many times I ran the server." I experienced no such stability issues, so your problems may lie elsewhere if that is happening (bad ram?)
const cheerio = require('cheerio');
const http = require('http');
const httpProxy = require('http-proxy');
const { ungzip } = require('node-gzip');
const host = 'https://github.com';
let proxy = httpProxy.createProxyServer({
secure: false,
changeOrigin: true
});
let option = {
target: host,
selfHandleResponse: true
};
proxy.on('proxyRes', function (proxyRes, req, res) {
console.log(`Proxy response with status code: ${proxyRes.statusCode} to url ${req.url}`);
if (proxyRes.statusCode == 301) {
throw new Error('You should probably do something here, I think there may be an httpProxy option to handle redirects');
}
let body = [];
proxyRes.on('data', function (chunk) {
body.push(chunk);
});
proxyRes.on('end', async function () {
let buffer = Buffer.concat(body);
try {
let $ = null;
const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
const decompressed = isCompressed ? await ungzip(buffer) : buffer;
const scriptTag = '<script src="my-customjs.js"></script>';
$ = cheerio.load(decompressed.toString());
$('body').append(scriptTag);
res.end($.html());
} catch (e) {
console.log(e);
}
});
});
let server = http.createServer(function (req, res) {
proxy.web(req, res, option, function (e) {
console.log(e);
});
});
console.log("listening on port 5051");
server.listen(5051);
I ended up writing a small Python Server using CherryPy and proxied the web app with mitmproxy. Everything is now working smoothly. Maybe I was doing it wrong with node-http-proxy but I also became sceptic about using it in a production environment.
I am troubling with nodejs proxy server modified(write) response.
I want to achieve auto login for one site via node proxy server and for that i have to query in database then i can modified response but it seems req ended before req.write and getting Error: write after end
Below is my implementation so far.
var express = require('express');
var proxy = require('http-proxy-middleware');
var options = {
target: 'http://example.com/', // target host
changeOrigin: true,
onProxyReq: function onProxyReq(proxyReq, req, res) {
var _write = res.write;
var body = "";
proxyReq.on('data', function(data) {
data = data.toString('utf-8');
body += data;
});
res.write = function (data) {
try{
//I have database query here instead of setTimeout
setTimeout(function(){
/* Modified response here and write */
_write.call(res, data); //can't write because req already end
},3000);
} catch (err) {
console.log('err',err);
}
}
}
}
// create the proxy (without context)
var exampleProxy = proxy(options);
// mount `exampleProxy` in web server
var app = express();
app.use('/', exampleProxy);
app.listen(8080);
Can anyone guide me how to achieve this ?
I am trying to make an HTTP POST request using an iOS Swift app to an Express.js server. In the post request, I send JSON data, creating the JSON object using a dict and SwiftyJSON. However, the request continues to time out. I think it has something to do with 'body-parser', which is what I am using to parse the HTTP body. Here is my swift code:
override func viewDidLoad() {
super.viewDidLoad()
var dict = ["name": "FirstChannel", "verified": 0, "private": 1, "handle": "firstChannel", "subscribers": 0] as [String : Any]
var jsonData = JSON(dict)
do {
let post:NSData = try jsonData.rawData() as NSData
var postLength: NSString = String(post.length) as NSString
var url = URL(string: "http://10.0.0.220:3000/channel/createChannel")!
var request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = post as Data
request.setValue(postLength as String, forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
NSURLConnection.sendAsynchronousRequest(request as URLRequest, queue: OperationQueue.main, completionHandler: { (resposne, data, error) in
if(error != nil) {
print(error)
}
else {
print(data)
}
})
}
catch {
print(error.localizedDescription)
}
}
And here is the code I use in my express.js router:
var express = require('express');
var router = express.Router();
var http = require('http');
var url = require('url');
var util = require('util');
var bodyParser = require('body-parser')
var ObjectID = require('mongodb').ObjectID;
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({extended: true}));
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');
var channelSchema = mongoose.Schema({
name: String,
verified: String,
private: String,
channelID: String,
handle: String,
subscribers: String
});
var Channel = mongoose.model("Channel", channelSchema);
router.post('/createChannel', bodyParser, function(req, res, next) {
req.body = true;
if(!req.body) return res.sendStatus(400);
var objID = new ObjectID();
var newChannel = new Channel({
name: req.body["name"],
verified: req.body["verified"],
private: req.body["private"],
channelID: objID,
handle: req.body["handle"],
subscribers: (req.body["subscribers"])
});
newChannel.save(function(err, point){
if(err) console.log(err);
else res.end();
});
});
If anybody could help me out and help this POST request succeed, I would greatly appreciate it. Thanks!
It doesn't look like you're sending back an HTTP 200 on success of your route - you only handle an error. Add a res.end(); at the end of your route (probably in the callback from the DB call) and try again.