I'm creating a simple app to practice connecting Vue to an Express server. I have a form that I'm attempting to send to the back end, but I can't seem to get my data to the back-end.
The error I'm receiving is:
POST http://localhost:8080/login 404 (Not Found)
My best guess is that the method in my Vue can't find a matching route on my server? If so, I'm confused as I have a route for login.
In my Vue script:
const axios = require('axios');
export default {
data: function() {
return {
user: {
email: '',
password: ''
}
}
},
methods: {
sub() {
var user = {
email: this.user.email,
password: this.user.password
}
axios.post('/login', user)
.then(res => console.log(res))
.catch(err => console.log(err))
}
}
}
On by back-end:
const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, '..')));
app.post('/login', function(req, res) {
console.log("Server HIT!!!!!!!!!!!!!!!!!!!!")
})
app.get('*', function (req, res) {
return res.sendFile('../index.html');
});
app.listen(3000);
console.log('Express server listening on port 3000');
Express is running on another port than your vue application. Vue is standard http which is 8080, but express runs on 3000 with this line:
app.listen(3000);
You are sending the request to /login, which from the point of view of your frontend is http://localhost:8080, but that's not where express is available.
Basically all you have to do is send the request to http://localhost:3000/login, simple as that.
By default express do not allow cross origin request i.e CORS. You have to enable it by setting middleware. add below lines in you server file and must be before declaring any routes
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
Related
I have a Node.js API running on port 81, and want to hit the endpoint from JavaScript like this:
function fetchFromApi() {
const axios = require('axios');
console.log('using port 81',axios.defaults);
axios.request({
method: 'get',
url:'/api/getAccountList',
port: 81, // port options is not valid - this does not have the desired result
})
.then( response => {
console.log(response);
const data = response.data;
const errors = (data.errors) ? data.errors : false;
if (errors) {
setErrors(errors);
}
})
.catch( reason => {
console.log(reason);
});
}
The network tab in chrome developer tools show this request still went to port 80.
When I try to code the entire protocol, port, host and url in the axios request, I get a CORS error:
axios.get('http://localhost:81/api/getAccountList')
Error is:
Access to XMLHttpRequest at 'http://localhost:81/api/getAccountList'
from origin 'http://localhost' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
My API server is a simple Node.js server:
const express = require('express');
const app = express();
const port = 81;
app.get('/api/getAccountList', (req, res) => {
const userIdBy = req.params.userIdBy;
const apiToken = req.params.apiToken;
if (!(userIdBy && apiToken)) {
res.status(200).json({errors:['Missing credentials']});
return true;
}
// check the user id and api token match up:
console.log('Hello');
});
app.listen(port);
How can I make my client query the API using HTTP on port 81?
CORS is a security feature in most browsers that disables cross-origin requests—i.e., requests from a different hostname. To surpass it, install the cors dependency on your Express server via npm using:
npm install cors
Then you need to add it to every app via the cors() function to every {{httpMethod}} you want to allow other domains to make requests to.
Try editing your code like this:
const express = require('express');
const cors = require('cors')
const app = express();
const port = 81;
app.get('/api/getAccountList', cors(), (req, res)=>{})
On the client side, to get Axios to GET from port 81 on the same host as the javascript is running I used:
import axios from 'axios';
//...
//...
axios.defaults.baseURL = window.location.protocol + "//" + window.location.hostname + ":81";
const result = await axios('/your/endpoint');
//...
//...
Can you try to add this to your Node.js server?
// Add headers
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:81');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
You can try to add only Access-Control-Allow-Origin header or modify others to your needs.
To achieve the required CORS protection AND avoid hard coding the servers FQDN / hostname, I used this code in my node api server:
const express = require('express');
const app = express();
const apiProviderPort = 81;
const allowedApiConsumerPort = 80;
app.use(function (req, res, next) {
const host = req.get('host'); // NOTE host is the fqdn:port
const hostSplit = host.split(':');
var fqdn;
if (hostSplit.length == 1) {
// I am not sure this is needed, it will be if hostname is fqdn[:port]
fqdn = host;
} else if (hostSplit.length == 2) {
fqdn = hostSplit[0];
} else {
console.log('Error the host contained multiple colons!');
}
console.log('protocol:',req.protocol,'host:',host,'fqdn:' + fqdn);
// next line edited March 2020 - I changed + '//' + to + '//:' +
// as the developer tools console showed
// The 'Access-Control-Allow-Origin' header contains the invalid value 'http//localhost:3000'.
const allowableOrigin = req.protocol + '//' + fqdn + ':' + allowedApiConsumerPort;
console.log('allowableOrigin:',allowableOrigin)
res.setHeader('Access-Control-Allow-Origin', allowableOrigin);
next();
});
app.get('/api/userDocReportData/', (req, res) => {
const userIdBy = req.params.userIdBy;
const apiToken = req.params.apiToken;
if (!(userIdBy && apiToken)) {
res.status(200).json({errors:['Missing credentials']});
return true;
}
// check the user id and api token match up:
// ...
// get your payload etc
res.status(200).json({errors:false,payload:{} });
});
app.listen(apiProviderPort);
I enhanced #webprogrammers answer above as I wanted code that could work in any environment (localhost; test.example.com, live.example.com etc)
My code:
void checkState() async {
print("CTC");
var url = "http://localhost:3000";
try {
var respX = await http.get(url);
} catch (err) {
print("response Arrived: $err");
}
}
But it is not possible:
https://github.com/flutter/flutter/issues/43015#issuecomment-543835637
I am using google chrome for debugging. simply pasting http://localhost:3000 allows me to connect to the URL from the same browser.
Is there any way to do it?
This issue was not with the flutter. It is the CORS policies in the browser as well as the server that blocked the request. I hosted it in a nodejs server with express. Here what I have did to solve this:
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
You can change the 'Access-Control-Allow-Origin' to the domain you are calling from if you want to. Else it will allow request from everywhere.
Remember, the localhost of your emulator is not the localhost of your machine. To test the API running on your machine you have to point to the ip adress of your computer
Web server listening at: http://localhost:3000
Browse your REST API at http://localhost:3000/explorer
D:\PPL\Laundry\Front\api\node_modules\mysql\lib\protocol\Parser.js:80
throw err; // Rethrow non-MySQL errors
^
ReferenceError: loopback is not defined
Please add this line to fix this Error
var loopback = require('loopback');
'use strict';
var loopback = require('loopback');
var boot = require('loopback-boot');
var app = module.exports = loopback();
app.use(function(req, res, next) {
var allowedOrigins = [
'http://localhost',
'http://localhost:3000',
'http://127.0.0.1',
'http://127.0.0.1:3000',
];
var origin = req.headers.origin;
if (allowedOrigins.indexOf(origin) > -1) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', true);
next();
});
app.start = function() {
// start the web server
return app.listen(function() {
app.emit('started');
var baseUrl = app.get('url').replace(/\/$/, '');
console.log('Web server listening at: %s', baseUrl);
if (app.get('loopback-component-explorer')) {
var explorerPath = app.get('loopback-component-explorer').mountPath;
console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
}
});
};
// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function(err) {
if (err) throw err;
// start the server if `$ node server.js`
if (require.main === module)
app.start();
});
This could be a sample server.js. Please make sure that loopback module is referred.
I am at the early stages of a simple tasks manager that I want to build with the MEAN Stack.
I can figure/resolve a simple routing issue. I don't see any error message in the terminal or console except for the 404 client error.
the root path is ok. I get a response back
I use html docs to render the ui for both.
this is how I have set up my server.js
var express = require('express')
var path = require('path')
var bodyParser = require('body-parser')
var index = require('./routes/index');
var tasks = require('./routes/tasks');
var app = express();
const port = '3456'
app.use('/', index)
app.use('api', tasks) <= HERE
//view engine
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.engine('html', require('ejs').renderFile);
//static folder
app.use(express.static(path.join(__dirname, 'client')))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))
app.listen(port, function() {
console.log('Starting the server at port' + port );
})
tasks.js
to render the template at the set route
var express = require('express')
var router = express.Router();
var mongojs = require('mongojs');
var db = mongojs('mongodb://sandy:cookie2080#ds147304.mlab.com:47304/tasklists_21092017', ['tasks'])
router.get('/tasks', function(req, res, next) {
res.send('api')
res.render('tasks.html')
db.tasks.find(function(err, tasks){
if (err) {
res.send('error message ' + err)
}
res.json(tasks)
})
})
module.exports = router;
and, index.js fyi
var express = require('express')
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index.html')
})
module.exports = router;
screenshot at the link below of the 404 error in browser after starting server on port 3456
404 error - screenshot
thanks for the help. I am sure it can be a little detail. it is very hard to debug though.
This error occurs because there's no route that handles the endpoint /api. What you can do here is create a middleware that will handle the /api. You can do it in your tasks.js like this:
tasks.js
router.get('/', function(req, res, next) {
res.send('This is api.')
})
Or if what you want to do is to direct the user from the endpoint /api to /api/tasks then you could do it like this:
router.get('/', function(req, res, next) {
res.redirect('/api/tasks')
})
Hope this helps.
I changed the port number. The issue was that the port 3000, was not responding to the requests, as it was still in use by an older process hence producing the warning
errno: 'EADDRINUSE',.
Just used the port 5000 to try out and it went through smoothly.
By the way I am using vs code.
I'm using Express 4.13.3 and my req.body is always empty on a GET request. It's filled with the correct data on POST request. Why is this? I couldn't find any reference to this difference in the Express docs.
My Express configuration:
function onError(err, req, res, next) { // eslint-disable-line no-unused-vars
// The error id is attached to `res.sentry` to be returned
// and optionally displayed to the user for support.
res.statusCode = 500; // eslint-disable-line no-param-reassign
res.end(`${res.sentry}\n`);
}
const render = require('../public/assets/SSR');
const app = express();
// sentry.io
app.use(raven.middleware.express.requestHandler(process.env.SENTRY_DSN));
const db = connectDb();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(cookieParser());
if (process.env.NODE_ENV === 'dev') {
// Hot reloading using existing express server
const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath,
}));
app.use(webpackHotMiddleware(compiler));
app.use(logger('dev'));
}
if (process.env.NODE_ENV === 'prod') {
app.use(helmet());
}
configPassport(app, passport, db);
configRoutes(app, passport, db);
app.use(ua.middleware(process.env.GA_TRACKING_ID, { cookieName: '_ga' }));
// sentry.io
// The error handler must be before any other error middleware
app.use(raven.middleware.express.errorHandler(process.env.SENTRY_DSN));
// Optional fallthrough error handler
app.use(onError);
app.get('*', render.default);
const port = process.env.PORT || 3000;
app.listen(port);
console.log(`Listening on port ${port}`);
console.log(`You are working in ${process.env.NODE_ENV} 😋`);
The body for a HTTP GET request should be empty. It's meaningless. While it's theoretically possible to add a request body to a GET requests, many clients don't or refuse and many servers strip it.
So in short: this is intentional. If you actually have a request body in a GET, remove it or switch to a more appropriate HTTP method.
RFC 7231, Section 4.3.1
A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.