I have a server running Express, and a client written in JS.
Using the following code on the client:
document.getElementById("continue").addEventListener("click", function() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
if(username != "" && password != "") {
const data = {
username, password
};
console.log(JSON.stringify(data));
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
fetch(urllogin, options).then(response => {
console.log(response.body);
});
}
And the following code on the server:
let port = 9000;
var express = require("express");
var fs = require("fs");
var https = require("https");
var app = express();
app.use(express.json())
app.use((req, res, next) => {
res.append('Access-Control-Allow-Origin', ['*']);
res.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.append('Access-Control-Allow-Headers', 'Content-Type');
next();
});
app.post("/login", (req, res) => {
console.log(req.body);
response = {
body:'hello'
};
res.json(JSON.stringify(response));
});
https
.createServer(
{
key: fs.readFileSync("server.key"),
cert: fs.readFileSync("server.cert"),
},
app
)
.listen(port, function () {
console.log(`Example app listening on port ${port}! Go to https://localhost:${port}/`);
});
I successfully receive the JSON object on the server, but on the client, I get:
{"username":"ok","password":"m"} script.js:20:21
ReadableStream { locked: false }
locked: false
<prototype>: ReadableStreamPrototype { cancel: cancel(), getReader: getReader(), pipeTo: pipeTo(), … }
script.js:29:25
Logged in the console (posted just a part of it).
Why does this happen, and how can I send data as a response to a POST request?
Thank you!
Related
I'm trying to setup CSRF tokens so that I can do a number of checks before issueing a token to the client to use in future requests.
Taking the guidance from the csurf documentation, I've setup my express route with the following:
const express = require('express');
const router = express.Router({mergeParams: true});
const csurf = require('csurf');
const bodyParser = require('body-parser');
const parseForm = bodyParser.urlencoded({ extended: false });
const ErrorClass = require('../classes/ErrorClass');
const csrfMiddleware = csurf({
cookie: true
});
router.get('/getCsrfToken', csrfMiddleware, async (req, res) => {
try {
// code for origin checks removed for example
return res.json({'csrfToken': req.csrfToken()});
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
router.post('/', [csrfMiddleware, parseForm], async (req, res) => {
try {
// this returns err.code === 'EBADCSRFTOKEN' when sending in React.js but not Postman
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
For context, the React.js code is as follows, makePostRequest 100% sends the _csrf token back to express in req.body._csrf
try {
const { data } = await makePostRequest(
CONTACT,
{
email: values.email_address,
name: values.full_name,
message: values.message,
_csrf: csrfToken,
},
{ websiteId }
);
} catch (error) {
handleError(error);
actions.setSubmitting(false);
}
Postman endpoint seems to be sending the same data, after loading the /getCsrfToken endpoint and I manually update the _csrf token.
Is there something I'm not doing correctly? I think it may be to do with Node.js's cookie system.
I think your problem is likely to be related to CORS (your dev tools will probably have sent a warning?).
Here's the simplest working back-end and front-end I could make, based on the documentation:
In Back-End (NodeJS with Express) Server:
In app.js:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
const cors = require('cors');
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
var app = express()
const corsOptions = {
origin: "http://localhost:3000",
credentials: true,
}
app.use(cors(corsOptions));
app.use(cookieParser())
app.get('/form', csrfProtection, function (req, res) {
res.json({ csrfToken: req.csrfToken() })
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
module.exports = app;
(make sure you update the corsOptions origin property to whatever your localhost is in React.
In Index.js:
const app = require('./app')
app.set('port', 5000);
app.listen(app.get('port'), () => {
console.log('App running on port', app.get('port'));
});
In React:
Create file "TestCsurf.js" and populate with this code:
import React from 'react'
export default function TestCsurf() {
let domainUrl = `http://localhost:5000`
const [csrfTokenState, setCsrfTokenState] = React.useState('')
const [haveWeReceivedPostResponseState, setHaveWeReceivedPostResponseState] = React.useState("Not yet. No data has been processed.")
async function getCallToForm() {
const url = `/form`;
let fetchGetResponse = await fetch(`${domainUrl}${url}`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": localStorage.getItem('xsrf-token'),
},
credentials: "include",
mode: 'cors'
})
let parsedResponse = await fetchGetResponse.json();
setCsrfTokenState(parsedResponse.csrfToken)
}
React.useEffect(() => {
getCallToForm()
}, [])
async function testCsurfClicked() {
const url = `/process`
let fetchPostResponse = await fetch(`${domainUrl}${url}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": csrfTokenState,
},
credentials: "include",
mode: 'cors',
})
let parsedResponse = await fetchPostResponse.text()
setHaveWeReceivedPostResponseState(parsedResponse)
}
return (
<div>
<button onClick={testCsurfClicked}>Test Csurf Post Call</button>
<p>csrfTokenState is: {csrfTokenState}</p>
<p>Have we succesfully navigates csurf with token?: {JSON.stringify(haveWeReceivedPostResponseState)}</p>
</div>
)
}
Import this into your app.js
import CsurfTutorial from './CsurfTutorial';
function App() {
return (
<CsurfTutorial></CsurfTutorial>
);
}
export default App;
That's the simplest solution I can make based on the CSURF documentations example. It's taken me several days to figure this out. I wish they'd give us a bit more direction!
I made a tutorial video in case it's of any help to anyone: https://youtu.be/N5U7KtxvVto
Currently I'm using the below code to connect with web service.
I need to connect to the Microsoft Azure Machine Learning Studio Api by using either Vue Axios or Express. Can someone help me.
var http = require("http");
var https = require("https");
var querystring = require("querystring");
var fs = require('fs');
function getPred(data) {
console.log('===getPred()===');
var dataString = JSON.stringify(data)
var host = 'ussouthcentral.services.azureml.net'
var path = '/workspaces/fda91d2e52b74ee2ae68b1aac4dba8b9/services/1b2f5e6f99574756a8fde751def19a0a/execute?api-version=2.0&details=true'
var method = 'POST'
var api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=='
var headers = {'Content-Type':'application/json', 'Authorization':'Bearer ' + api_key};
var options = {
host: host,
port: 443,
path: path,
method: 'POST',
headers: headers
};
console.log('data: ' + data);
console.log('method: ' + method);
console.log('api_key: ' + api_key);
console.log('headers: ' + headers);
console.log('options: ' + options);
var reqPost = https.request(options, function (res) {
console.log('===reqPost()===');
console.log('StatusCode: ', res.statusCode);
console.log('headers: ', res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
});
// Would need more parsing out of prediction from the result
reqPost.write(dataString);
reqPost.end();
reqPost.on('error', function(e){
console.error(e);
});
}
//Could build feature inputs from web form or RDMS. This is the new data that needs to be passed to the web service.
function buildFeatureInput(){
console.log('===performRequest()===');
var data = {
"Inputs": {
"input1": {
"ColumnNames": ["gl10", "roc20", "uo", "ppo", "ppos", "macd", "macds", "sstok", "sstod", "pmo", "pmos", "wmpr"],
"Values": [ [ "0", "-1.3351", "50.2268", "-0.2693", "-0.2831", "-5.5310", "-5.8120", "61.9220", "45.3998", "-0.0653", "-0.0659", "-30.3005" ], ]
},
},
"GlobalParameters": {}
}
getPred(data);
}
function send404Reponse(response) {
response.writeHead(404, {"Context-Type": "text/plain"});
response.write("Error 404: Page not Found!");
response.end();
}
function onRequest(request, response) {
if(request.method == 'GET' && request.url == '/' ){
response.writeHead(200, {"Context-Type": "text/plain"});
fs.createReadStream("./index.html").pipe(response);
}else {
send404Reponse(response);
}
}
http.createServer(onRequest).listen(8050);
console.log("Server is now running on port 8050");
buildFeatureInput();
But can i do this by using axios call or express server.
can anyone help me with proper syntax if i can do this using either vue axios or express server.
It sounds like you want to use express in server with axios in Vue front page instead of Node http server with https client in server-side.
To replace Node http with express is very easy, it is as below.
const express = require('express')
const path = require('path');
const app = express()
const port = 8050
app.use(express.static(path.join(__dirname, '.')))
app.get('/', (req, res) => res.sendFile('index.html'))
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err)
})
app.use(function (err, req, res, next) {
if(err.status == 404) {
res.status(404).send("Error 404: Page not Found!")
}
res.status(500).send("Error 500: Internal Error!")
})
app.listen(port, () => console.log("Server is now running on port 8050"))
But consider for the security of the api-key value for calling Azure Machine Learning Studio API, I recommended not to call the API with axios in Vue front page and still make the calling works in the server-side by express, as below.
const axios = require('axios');
var host = 'ussouthcentral.services.azureml.net'
var path = '/workspaces/fda91d2e52b74ee2ae68b1aac4dba8b9/services/1b2f5e6f99574756a8fde751def19a0a/execute?api-version=2.0&details=true'
var api_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=='
const pred = axios.create({
baseURL: 'https://'+host,
timeout: 1000,
headers: {'Content-Type':'application/json', 'Authorization':'Bearer ' + api_key}
});
app.post('/mls-api', (req, res) => pred.post(path, JSON.stringify(req.body)).then(function(resp) {
resp.pipe(res)
}))
Then, you can call /mls-api url from Vue front page with the data value below.
var data = {
"Inputs": {
"input1": {
"ColumnNames": ["gl10", "roc20", "uo", "ppo", "ppos", "macd", "macds", "sstok", "sstod", "pmo", "pmos", "wmpr"],
"Values": [ [ "0", "-1.3351", "50.2268", "-0.2693", "-0.2831", "-5.5310", "-5.8120", "61.9220", "45.3998", "-0.0653", "-0.0659", "-30.3005" ], ]
},
},
"GlobalParameters": {}
}
axios.post('/mls-api', data)
.then(function (response) {
console.log(response);
})
So I have been researching for hours and trying different things and have been researching for hours to no avail. The call is to get a JWT token after providing user and pass.
function listenForLogin() {
console.log('listening')
$('#submit-btn').on('click', e => {
e.preventDefault();
console.log('button-pressed');
const username = $('#user-input').val().trim();
const password = $('#pass-input').val().trim();
var user = {}
user.username = username;
user.password = password
console.log(user);
$('#user-input').val('');
$('#pass-input').val('');
authenticateUser(user);
});
}
//send to autenticate
function authenticateUser(user) {
console.log('trying to authenticate');
const settings = {
url:"/api/auth/login",
data: JSON.stringify(user),
dataType: "json",
method:"POST",
success: (data) => {
console.log('authenticated user');
redirectWithToken(data.authToken, user);
},
error: (err) => console.log(err)
}
$.ajax(settings);
}
When it hits the server morgan sees that there was a request but i get back a status of 400. here is my routes
'use strict';
const express = require('express');
const passport = require('passport');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const {JWT_SECRET, JWT_EXPIRY} = require('dotenv').config();
const router = express.Router();
const createAuthToken = function(user) {
return jwt.sign({user}, 'shade', {
subject: user.username,
expiresIn: '7d',
algorithm: 'HS256'
});
};
const localAuth = passport.authenticate('local', {session: false});
router.use(bodyParser.json());
router.post('/login', localAuth, (req, res) => {
const authToken = createAuthToken(req.user.serialize());
res.json({authToken});
});
const jwtAuth = passport.authenticate('jwt', {session: false});
router.post('/refresh', jwtAuth, (req, res) => {
console.log('refresh targeted');
const authToken = createAuthToken(req.user);
res.json({authToken});
});
router.get('/dashboard/:user', jwtAuth, (req, res) => {
res.redirect(`https:flow-state.herokuapp.com/dashboard/${req.params.user}`);
})
module.exports = router;
and I am having a hard time understanding how passport.authenticate('localAuth') works so here is my strategies file just in case you need that
Update: I am getting some kind of error when checking the requests on fiddler.
RESPONSE BYTES (by Content-Type)
~headers~: 132
~???????~: 11
anybody got any clue what that means?
Did you miss the content-type in the ajax settings?
Add contentType: "application/json" in the ajax settings and try again.
Note :
dataType defines the data type expected of the server response.
contentType defines the data type of the content which will be sent to the server. Default is: "application/x-www-form-urlencoded"
8 hours later and a big headache a solution is here. #vignz.pie you were right but I needed to send the 'Content-Type': 'application/json' in the headers along with strigify the data setting the processData: false did the trick. Thanks for the help!
function listenForLogin() {
console.log('listening')
$('#submit-btn').on('click', e => {
e.preventDefault();
console.log('button-pressed');
const username = $('#user-input').val().trim();
const password = $('#pass-input').val().trim();
$('#user-input').val('');
$('#pass-input').val('');
authenticateUser(username, password);
});
}
//send to autenticate
function authenticateUser(user, pass) {
var info = {
username: user,
password: pass
};
console.log(info)
const settings = {
url:"/api/auth/login",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify(info),
processData: false,
dataType: "json",
method:"POST",
success: (data) => {
console.log('authenticated user');
redirectWithToken(data.authToken, user);
},
error: (err) => console.log(err)
}
$.ajax(settings);
}
I have this code in Ionic app but I don't know how to make an API with Node.js to send this values to sever only by using Node.js.
submitForm() {
let headers = new Headers(
{
'Content-Type': 'application/json',
'Accept': 'application/json'
});
let options = new RequestOptions({ headers: headers });
let data = JSON.stringify({
Value1: this.form.value1,
Value2: this.form.value2,
Value3: this.form.value3
});
console.log(data);
let url = 'http://localhost:3000/calculate';
console.log(url);
return new Promise((resolve, reject) => {
this.http.post(url, data, options)
.toPromise()
.then((response) => {
console.log('API Response : ', response.status);
resolve(response.json());
})
.catch((error) => {
console.error('API Error : ', error.status);
console.error('API Error : ', JSON.stringify(error));
reject(error.json());
});
});
}
You may like to use ExpressJS. Following example may help you
Create a directory lets called api with following 2 files
create app.js in api directory
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/calculate', function(req, res) {
var data = req.body;
console.log('Here are your data: ', data);
res.json({message: 'you posted successfully'});
});
var port = process.env.PORT || 3000;
var server = http.createServer(app);
server.listen(port);
server.on('error', function(){
console.error('Error')
});
server.on('listening', function(){
console.log('server started on port ' + port)
});
create package.json file in api directory
{
"name": "api",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"body-parser": "~1.17.1",
"express": "~4.15.2"
}
}
now open command line/terminal and install dependencies by running following command(you must go to inside api directory)
npm install
now you can run by just running either npm start or node app.js
You should google for learning and studying and post questions for bug/issue
Update: without any dependencies or library but not recommended
It will be better to use http framework like express, sailsjs, etc. but if you like to play with nodejs then following example may help you
var http = require('http');
var port = process.env.PORT || 3000;
var server = http.createServer(function(req, res) {
var contentType = req.headers['content-type'];
var rawData = '';
req.on('data', function (chunk) {
rawData += chunk;
});
req.on('end', function () {
if(req.method === 'POST' && req.url === '/calculate' && contentType.indexOf('application/json')>-1){
try {
const data = JSON.parse(rawData);
console.log('Your data is here: ', data);
res.writeHead(200, { 'Content-Type': 'application/json'});
var result = {message: 'you have posted successfully'}
res.end(JSON.stringify(result));
} catch (e) {
console.error(e.message);
res.writeHead(400, { 'Content-Type': 'application/json'});
var result = {message: e.message}
res.end(JSON.stringify(result));
}
} else {
res.writeHead(404, { 'Content-Type': 'application/json'});
var result = {message: 'Url not found'}
res.end(JSON.stringify(result));
}
});
});
server.listen(port);
server.on('error', function(){
console.error('Error')
});
server.on('listening', function(){
console.log('server started on port ' + port)
});
I've created an example Node.js project that illustrates client/server request/response using AJAX and JSON. It "requires" only 'http', 'path', and 'fs'.
It implements a 'calculate' function server-side, and has a web page that presents 3 input boxes and a 'Calculate' button.
It's on Github: "https://github.com/bobwirka/NodeClientServer.git"
Hope this will be of help.
I had a problem in req.body at server as i received req.body as {} empty, here is the code at service
addEmployeeCollection(addArray: EmployeeSchema) {
let url: string = Constants.DOMAIN + Constants.CREATE_EMPLOYEE_ROUTE;
console.log('addArray at employee service', addArray)
var body = addArray;
return this._httpService.post(url, body).map(res => res.json()).catch(this._errorHandler);
}
this._httpService.post(url, body) will go to the interceptor, there the http.post method returned, here is the interceptor code,
post(url: string, body: Object, options ? : RequestOptionsArgs): Observable < Response > {
this.headers.append('Content-Type', 'application/json');
let token = localStorage.getItem('realtoken');
console.log('http token', token);
if (typeof url === 'string') {
if (!options) {
options = {
headers: this.headers
};
}
options.headers.set('Authorization', ` ${token}`);
}
return super.post(url, body, options).catch(this.catchAuthError(this));
}
now here the request payload at headers contains the information,
The response from the server side is
{"__v":0,"_id":"58ba4969ed69821fd6f7e573"}// details of employee is not saved
here the server side code
var mongoose = require('mongoose');
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
//schema-models
var employeeCollection = require('../../model/employee.model.js');
router.post('/new', function(req, res) {
var employee_data = req.body;
console.log('req.body=====> ', req.body)
var addcontent = new employeeCollection(employee_data);
console.log('addcontent--->', addcontent);
addcontent.save(function(err, data) {
if (err) {
res.send(err);
} else {
console.log('data', data);
res.json(data);
}
});
});
module.exports = router;
At terminal, req.body=====> {}, the employee details are sent correctly in the request, but at server side am getting as empty req.body
As a beginner to this concepts,i could not figure out where i am getting wrong, please help me out