NodeJS server can't retrive post data from Angular - node.js

I have a backend server writen in NodeJS, which use express.
I have the latest Angular as frontend, I post a data (GPG file) to the nodeJS server, and I try to get that data in NodeJS code, and print it out in the server console, but all I get is an empty object.
All I want to do is to either pass the Blob data to node server, or to pass a plain text to node server, and read it from node code.
const express = require('express'),
app = express(),
port = process.env.PORT || 3000;
app.listen(port);
const cors = require('cors');
app.use(cors());
//create a cors middleware
app.use(function (req, res, next) {
//set headers to allow cross origin request.
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/decrypt', (res, req) => {
// Here I try to access the data that I passed by POST method
console.log(res.body);
return 'data back';
})
This is my Angular Code:
import { Injectable, Input } from '#angular/core';
import { HttpClient, HttpResponse, HttpHeaders } from '#angular/common/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import { Observable } from 'rxjs/Observable';
import { saveAs } from 'file-saver/FileSaver';
#Injectable()
export class DatabaseService {
private API_GET_LIST_FILES = 'http://localhost:3000/files';
private API_GET_FILE = 'http://localhost:3000/download?name=';
private BASE_URL = 'http://localhost:3000/';
constructor(private http: HttpClient) { }
getFile(key: string) {
return this.http.get(this.API_GET_FILE + key, {
responseType: 'blob'
})
.map(res => {
return {
filename: key.split('/').pop(),
data: res
};
})
.subscribe(res => {
console.log('start download:', res);
// no matter what I pass here to the decrypt function, I can't get it in nodeJS server
this.decrypt(res.filename)
.subscribe(
next => console.log(next)
);
saveAs(res.data, res.filename);
}, error => {
console.log('download error:', JSON.stringify(error));
}, () => {
console.log('Completed file download.');
});
}
decrypt(res): Observable<any> {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/octet-stream'
})
};
return this.http.post(this.BASE_URL + 'decrypt', res, httpOptions);
}
}
If I pass the ***res*** to the decrypt function, I will get a lot info but looks weird to me.

Do what Anand suggested, set headers to application/json (or just skip httpOptions completely as that is default) and send {name: res}. Request body then should be just that.
For file upload you should use Express middleware like Multer or Multiparty. On Angular side for example ng2-file-upload.
Express method callback signature is (req, res, next) not (res, req), it is confusing when reading your code :(
And if you just return from callback, it will hang until http request times out (I think). You should do res.status(200).end() or res.json({done: true}) or anything similar.

Related

Angular post request to NodeJS JSON error

So i am sending a POST request to a nodeJS app, my request in Angular looks like this:
export class SearchComponent {
constructor(private http: HttpClient) {}
newWord = '';
keyword = '';
onClick() {
const headers = new HttpHeaders()
.set('Authorization', 'my-auth-token')
.set('Content-Type', 'application/json');
this.http
.post('http://localhost:3000/search', JSON.stringify(this.keyword), {
responseType: 'text',
headers: headers,
})
.subscribe((data) => {
this.newWord = data;
});
}
}
When i try to console.log the request i get an Unexpected token " in JSON at position 0 error even though i tried all the solutions i could find on stackoverflow this is how my NodeJS app is set and the error:
const bodyParser = require("body-parser");
const express = require("express");
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.all("/*", function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
res.header(
"Access-Control-Allow-Headers",
"Content-Type, Authorization, Content-Length, X-Requested-With"
);
next();
});
app.listen(3000, () => {
console.log("Server is running on port 3000");
});
app.post("/search", (req, res) => {
res.send(req.body);
});
The error i get is this:
SyntaxError: Unexpected token " in JSON at position 0
at JSON.parse (<anonymous>)....
Note that the this.keyword gets its value from a input field if i dont use JSON.stringify no error is happening but the req variable is "undefined".
Assuming you are asking how to get back the data. I'm not sure if this will work, but you can give it a try:
Under comments, see that you mean this.keyword. Here is the change I would make
going by axis format, this may be incorrect
.post('http://localhost:3000/search', JSON.stringify(this.keyword), {
responseType: 'text',
headers: headers,
})
instead, try:
.post('http://localhost:3000/search', {
keyword: this.keyword, // changed this
responseType: 'text',
headers: headers,
})
also in your server, you can change to this:
const app = express();
app.use(express.json())
app.use(express.text())
app.use(express.urlencoded({ extended: true }))
(body parser included in express now)
new to the mern stack (have never used Angular) so kind of iffy but hopefully that can help

CORS error when using Cloud Functions for Firebase

This is my first question posed, so I apologize if it is not formatted well.
I have been trying to figure out how to deal with the following CORS error, as well as, the CORS preflight error:
...has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'https://example.com/' that is not equal to the supplied origin.
I have spent the last few days reading every question on this topic, and all other documentation I could find on CORS/Cloud Functions/Axios/etc. I am using React, Node, Express, Axios, Google Firebase to host, and Google Cloud Functions.
I am trying to access the PayPal API to gain a bearer token to make further API requests. I understand some of the code pertaining to the request headers might be redundant. I have just been trying to throw anything at this.
Does anyone have any ideas?
The node file - index.js
const axios = require("axios");
const express = require("express");
const cors = require("cors")({ origin: true });
const app = express();
app.use(cors());
app.use(express.json());
app.post("/v1/oauth2/token/", cors(), (req, res) => {
res.set("Access-Control-Allow-Origin", "https://example.com/");
var data = qs.stringify({
grant_type: "client_credentials",
});
var config = {
method: "post",
url: "https://api-m.sandbox.paypal.com/v1/oauth2/token/",
headers: {
"Access-Control-Allow-Origin": "https://example.com/",
Authorization:"xyz",
"Content-Type": "application/x-www-form-urlencoded",
},
data: data,
};
axios(config)
.then(function (response) {
let bearerToken = response.data.access_token;
res.status(201).send(bearerToken);
})
.catch(function (error) {
console.log(error);
});
});
exports.api = functions.https.onRequest(app);
The react file - payment.js
import axios from "../axios/axios";
const oneTimePaypalPayment = async () => {
const response = await axios.post("/v2/checkout/orders");
console.log(response);
};
The axios file - axios.js
import axios from "axios";
const instance = axios.create({
headers: {
"Access-Control-Allow-Origin": "https://example.com/",
"Access-Control-Allow-Headers": "https://example.com/",
},
baseURL: "https://us-central1-example.cloudfunctions.net/api/"
});
export default instance;
What I have tried
I have tried using the wildcard " * " just to try to get it to work but no luck. I read on another answer that Google Cloud Functions do not recognize the '*' anyways. I have also tried all of the code below, and a lot of other ways to manipulate the Access-Control-Allow-Origin on the request header
const allowCrossDomain = function (req, res, next) {
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
next();
};
app.use(allowCrossDomain);
app.all("*", (req, res, next) => {
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
next();
});
const corsOptions = {
origin: "https://example.com/",
};
app.use(cors(corsOptions))
app.options("/v1/oauth2/token", cors(corsOptions));
app.use(cors({origin:true}));
Any thoughts would be greatly appreciated
In a cloud function that you are exporting or working with use below for Origin :
exports.your function = async (req, res) => {
res.set('Access-Control-Allow-Origin', '*');

Getting back empty response body when making a POST request using Angular + Express

I'm trying to make a simple POST request but I'm getting an empty response back from the server. I've sifted through all the SO questions regarding this topic and tried the solutions posted but to no avail.
I've tried changing the request header options to use 'application/x-www-form-urlencoded' and set bodyParser in my express app as app.use(bodyParser.urlencoded({ extended: true })); but that didn't work either.
auth-service.service.ts
login(loginInfo: object) {
return this.http.post<loginInfo>(this.loginUrl, { "test": "test" })
.pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
console.log('An error occured:', error.error.message);
} else {
console.log(`Backend returned code ${error.status}, ` +
`body was ${error.error}`);
}
return throwError('Something bad happened; please try again later.')
}
login.component.ts (calls the login service method)
onSubmit() {
const loginInfo = { username: this.username.value, password: this.password.value };
this.authService.login(loginInfo).subscribe(
resp => { console.log(resp); },
err => { console.log(err); }
)
}
server.js (I've defined routes here but they're not relevant)
const express = require('express');
const bodyParser = require('body-parser');
const api = require('./routes/api');
const app = express();
const port = process.env.port || 3000;
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
next();
})
app.use(bodyParser.json());
app.use('/api', api)
app.get('/', function (req, res) {
res.send(JSON.stringify('Hello from server'));
})
app.post('/login', (req, res) => {
let userData = req.body
res.send('Request body: ' + JSON.stringify(userData));
})
app.listen(port, function () {
console.log('Server running on localhost: ' + port);
});
I'm console logging the following:
Backend returned code undefined, body was undefined
Something bad happened; please try again later.
When I try using Postman, however, I get the response I expect (i.e. Request body: {})
I'm not sure as to why a response is retrieved when done through Postman but not when done through the app.
Any help is appreciated. Thanks!
You need to set body for POST request in auth-service.service.ts:
import { HttpParams } from '#angular/common/http';
login(loginInfo: object) {
const body = new HttpParams()
.set('test', 'test');
return this.http.post<loginInfo>(this.loginUrl, body)
.pipe(
catchError(this.handleError)
);
}
try using express.json its missing
app.use(express.json());
and
app.use(bodyParser.urlencoded({
extended: true
}));

How to read data in node.js app.js from IONIC typescript through REST API?

My service.ts is like this :
import { Injectable } from '#angular/core';
import {Http, Headers} from '#angular/http';
import 'rxjs/add/operator/map';
/*
Generated class for the PeopleSearch provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class PeopleSearch {
data: {name:'morr', age: 19, email:'mor#mo.com' };
apiurl: "http://localhost:3082";
constructor(public http: Http) {
console.log('Hello PeopleSearch Provider');
}
load1() {
return new Promise(resolve => {
let headers = new Headers();
this.http.post('http://localhost:3082/users/u/',JSON.stringify(this.data),{ headers: headers })
.map(res => res.json())
.subscribe(data => {
//console.log(data.user1);
resolve(data);
});
});
}
And my app.js is like this :
const express= require('express')
const app= express();
const morgan= require('morgan')
const mysql= require('mysql')
var cors = require('cors');
app.use(cors());
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const connection= mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test'
})
app.use(morgan('combined'))
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
res.header("Access-Control-Allow-Methods", "GET, PUT, POST");
if ('OPTIONS' === req.method) {
res.status(204).send();
}
else {
next();
}
});
app.post("/users/u", (req, res) => {
const name=req.body.name
const age= req.body.age
const email= req.body.email
const querystring="insert into users values(?,?,?,?)"
connection.query(querystring, [11,name,age,email],(err,results,fields)=>{
console.log("success sql post")
res.end()
})
})
app.listen(3082, () => {
console.log("Server is up and listening on 3082...")
})
I am not getting where I am exactly wrong. If I write data hardcoded in all variables, username age and email, then post req is executing successfully. But when I am using req.body to get the data posted by typescript then i think Its not reading properly.
can anyone suggest what to use or how to use req.body to get the data in variables and save it in query??
You have not defined your data correctly in the PeopleSearch service. Take a close look at the top of the PeopleSearch class. This:
#Injectable()
export class PeopleSearch {
data: {name:'morr', age: 19, email:'mor#mo.com' };
apiurl: "http://localhost:3082";
Should be (note the '=' instead of ':'):
#Injectable()
export class PeopleSearch {
data = {name:'morr', age: 19, email:'mor#mo.com' };
apiurl = "http://localhost:3082";
The Typescript syntax for defining a property in a class is:
[name]:[type] = [value]
In your case you have defined the name and the type but not the value. Effectively you defined the property data and set the type so only objects exactly matching the properties and values you defined can be set to it.

How changing hard coded url routing in angular for production

I have deployed Angular/ NodeJS app on Heroku I get this error :
Mixed Content: The page at 'https://lit-island-95274.herokuapp.com/signup' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://localhost:4001/login'. This request has been blocked; the content must be served over HTTPS.
I think that the problem is about static urls that should be relative to the base Url of web server.
.Ts file
import { Injectable } from '#angular/core';
import { Headers, Http } from '#angular/http';
import { User } from './user';
#Injectable()
export class LoginService {
private headers = new Headers({ 'Content-Type': 'application/json' });
private loginUrl = 'http://localhost:4001/login'; // URL to web api
private registerUrl = 'http://localhost:4001/register';
constructor(private http: Http) { }
Login(login: User): Promise<number> {
console.log("login", login.username);
return this.http
.post(this.loginUrl, JSON.stringify(login), { headers: this.headers })
.toPromise()
.then((res) => res.json().login as number)
}
Register(register: User): Promise<any> {
return this.http
.post(this.registerUrl, JSON.stringify(register), { headers: this.headers })
.toPromise()
.then((res) => res.json().added as number)
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}
Here's the nodeJS Index.js file .
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
var cool = require('cool-ascii-faces');
//var db = require('./db/connect.js');
// Get our API routes
//const api = require('./server/routes/api');
var appRoutes = require('./routes/index');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'client/dist/')));
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT ,DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.use('/', appRoutes)
// Set our api routes
//app.use('/api', api);
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'client/dist/index.html'));
});
app.get('/cool', function(request, response) {
response.send(cool());
});
const port = process.env.PORT || '4001';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`API running on localhost:${port}`));
If I have understood , instead of having http://localhost:4001/login I should get https://lit-island-95274.herokuapp.com/login. And this should be done automatically when deploying my app.
But I have no idea how to made that.
private loginUrl = 'http://localhost:4001/login'; // URL to web api
private registerUrl = 'http://localhost:4200/register';
if they are indeed hosted locally, its as easy as loginUrl = '/login'; or you could simply add the s to http, private loginUrl = 'https://localhost:4001/login'; Just fetch the urls over https. The problem is with the type of insecure fetch, not relative versus static urls.

Resources