express and static assets with external resources - express

I am using Express to serve static assets. Frontend is AngularJS 1.x and I have html5mode enabled. Trying to implement Recaptcha is where I noticed the following in Chrome dev tools:
Uncaught SyntaxError: Unexpected token <
api.js?onload=vcRecaptchaApiLoaded&render=explicit“:1
When I click on the function to initiate the Recaptcha process I receive:
Error: reCaptcha has not been loaded yet.
So far this makes sense to be bacause I noticed the string that the first error is reporting is part of the url path to load Recaptcha from Google.
When I click on the url (api.js?onload=vcRecaptchaApiLoaded&render=explicit“:1) in chrome tools it loads my index.html! Strange!
This has be believing it has something to do with my static asset serving. I have played around with my express server until the cows came home and cannot figure out how to remedy.
Live example:
http://ninjacape.herokuapp.com
Here is my code and thank you for taking a look!
index.html
<script src=“https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit“ async defer></script>
express.js
var express = require('express');
var compression = require('compression');
var app = module.exports.prod = exports.prod = express();
var devAPI = 'http://localhost:1337';
app.use(compression());
app.use(express.static('.tmp'));
app.get('/*', function(req, res) {
res.sendFile(__dirname + '/.tmp/index.html');
});
var proxy = require('express-http-proxy');
app.use('/api', proxy(devAPI));
var port = process.env.PORT || 8000;
app.listen(port);

Well... I wish I had a better answer however I am just happy I got it to work. Something in the way I am statically serving files is appending any url in index.html to http://localhost:8000. To work around this I took a look at the actual request coming into Express and found the url. Then added logic to redirect that request to the real url. See commented code below for more info:
// Any requests matching /*
app.get('/*', function(req, res, next) {
// Log the original url express is tying to go to
console.log(req.url);
// This is the url found from the step above (Where are the extra characters coming from?!)
var url ='/%E2%80%9Chttps://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit%E2%80%9C'
// Self explanatory
if (req.url === url) {
// Respond by redirecting the request
res.redirect('https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit')
//End this block and continue
next();
} else {
// If it doesn't match the above url, proceed as normal
res.sendFile(__dirname + '/.tmp/index.html');
}
});

Related

Express routes and middleware with Firebase Cloud Functions

Question
How do I use Express within Firebase Cloud Functions?
Expectations
Using either of the URLs I've setup, I expect to see, "Hello from Express on Firebase!" in the console logs.
Why? My understanding is, "*" means all routes requested should response.send("Hello from Express on Firebase!");
app.get("*", (_request, response) => {
response.send("Hello from Express on Firebase!");
});
Issue
When I use, https://us-central1-myapp.cloudfunctions.net/helloWorld I get the expected Hello from Firebase! in the logs. Should I also see "Hello from Express on Firebase!"?
When I use, https://us-central1-myapp.cloudfunctions.net/api, I get a 404 error
The URL, https://us-central1-myapp.cloudfunctions.net/api is the issue. See why in the answer below.
Code
// Express
import express = require("express");
const app = express();
const cors = require("cors")({
origin: "*"
});
app.use("*", cors);
// Firebase Functions SDK
import functions = require("firebase-functions");
app.get("*", (_request, response) => {
response.send("Hello from Express on Firebase!");
});
exports.api = functions.https.onRequest(app);
exports.helloWorld = functions.https.onRequest((_request, response) => {
response.send("Hello from Firebase!");
});
tl;dr
An example of what I'm hoping to accomplish is here, but none of the code examples worked for me. I get I get a 404 error with each one.
The Express Documentation here shows a similar HelloWorld example, but I confuse how Firebase takes the place of app.listen(3000, () => console.log('Example app listening on port 3000!'))
Is cors working properly in my example code? Although I get the expected response and log, Chrome console warns: Cross-Origin Read Blocking (CORB) blocked cross-origin response https://appengine.google.com/_ah/lo....
I have a Slack App that is hitting these URLs (I hit them with chrome too). Eventually, I'd like to use Botkit middleware in my Google Cloud Functions. I don't yet grasp proper setup of Express app.use() and app.get()
Answer
I made a simple mistake by treating /api as a function when it's actually a part of the path.
By using this URL with the trailing /
https://us-central1-myapp.cloudfunctions.net/api/
I'm now hitting the Express route and function.

Express: serve static files on subroute

I'm trying to get routing work using Express and create-react-app.
My goal is to address the user to the homepage of the application when the URL is / and to the login page when the URL matches /login.
In my server.js I have two routes defined:
var mainRoutes = require("./routes/mainRoutes");
var apiRoutes = require("./routes/apiRoutes");
[...]
app.use("/", mainRoutes);
app.use("/api", apiRoutes);
While apiRoutes contains all the api routing definitions, mainRoutes is responsible for the main navigation (at least this was the idea):
var express = require("express");
var path = require("path");
let router = express.Router();
router.route("/").get((req, res, next) => {
res.sendFile("index.html", { root: "./client/build/" });
});
router.route("/login").get((req, res, next) => {
res.send("This is the login page");
});
module.exports = router;
Somewhere I read about serving the static asset generated by the building process of create-react-app so I added:
// Priority serve any static files.
app.use(express.static(path.join(__dirname, "client/build")));
// All remaining requests return the React app, so it can handle routing.
app.get("*", function(req, res) {
res.sendFile(path.join(__dirname + "/client/build/index.html"));
});
Adding these lines, I successfully see my index.html but I can't visit both /login and /apisubroutes since it redirect me on the main page (index.html) each time.
It's like I need to serve the static files on my subroute mainRoutes but I don't have an idea on how to do that.
How can I make this work?
app.get('*') would match every single route that you have.
You should do something like this:
var mainRoutes = require("./routes/mainRoutes");
var apiRoutes = require("./routes/apiRoutes");
[...]
app.use(express.static(path.join(__dirname, "client/build")));
app.use("/", mainRoutes);
app.use("/api", apiRoutes);
// If the app reaches this point, it means that
// the path did not match any of the ones above
app.use(function(req, res, next){
// redirect the user to where we serve the index.html
res.redirect('/');
});
create-react-app I believe handles routing different, you cannot hook up the browser's route to the route you want to serve because you're running a single page application", unless you do universal routing with server and the js bundle

Serving static files from an express/node.js application

Hi I am a newbie and started to learn about node recently. I took an Heroku tutorial on websockets (https://devcenter.heroku.com/articles/node-websockets) and adapted it for a specific project I was working on. In the example code there was a single index.html file with some embedded javascript. I moved this script out to a separate file and referenced it in the HTML. Everything worked fine locally but doesn't work when i deploy to Heroko. I chatted with the very helpful team at Heroku who informed me that my server side code is serving up all files as HTML and I need to change the code. They gave me some pointers and I tried as many things as I could over several days but to no avail. In the end they recommended coming to this forum as a way to solve the problem as it is beyond their scope. The existing code that serves up the index.html file is as follows:
const express = require('express');
const SocketServer = require('ws').Server;
const path = require('path');
const PORT = process.env.PORT || 3000;
const INDEX = path.join(__dirname, 'index.html');
const server = express()
.use((req, res) => res.sendFile(INDEX) )
.listen(PORT, () => console.log(Listening on ${ PORT }));
At first i edited this to include the line:
app.use(express.static('public'))
but this didn't work. I then amended as follows and it still doesn't work:
const INDEX = path.join(__dirname, 'index.html');
const JS = path.join(__dirname, 'client.js');
const server = express()
.use((req, res) => {
res.sendFile(INDEX);
res.sendFile(JS);
I have looked at other tutorials that work when i run them in isolation but when I try to adapt my above code it simply doesn't work. I would really appreciate if someone out there could point me in the right direction.
BTW this is what Heroku told me:
"To explain a bit further this error Uncaught SyntaxError: Unexpected token < is because the URL for http://thawing-journey-33085.herokuapp.com/client.js isn't serving a javascript file but is instead trying to serve the HTML for the homepage. This suggests you have an issue with the routing in your application which you'll need to review. This is probably because your server.js file doesn't check for any particular URL before sending the index.html file."
Thanks
I serve my static files like this:
// define the folder that will be used for static assets
app.use(Express.static(path.join(__dirname, '../public')));
// handle every other route with index.html, which will contain
// a script tag to your application's JavaScript file(s).
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, '../public', 'index.html'));
});
This way i set the static folder in the express.static middleware so i can serve the files. And then i redirect all url request to the index.html
To know more: express static

Ember app served from express urls don't work after refresh

In ember I build for production into the /client folder in my express app. In express at the bottom just before I start the app I have these lines
var api = require('./app/routes/api');
app.use('/api/v'+apiVersion, api);
app.use(express.static(__dirname + '/client'));
That works up until I refresh the page at which point it returns a Cannot GET for that route, in my logs from morgan in the terminal I see it's making a call to /url_here instead of routing to the index.html file and allowing ember to take over from there. Do I need to set this up a different way?
Your express app need to handle 404 error and send 'index.html' of client app.
Add this code at the very bottom (below all others):
app.use('/assets', express.static(__dirname + '/client/assets'));
app.use(function(req, res, next) {
res.sendfile(__dirname + '/client/index.html');
});

Can't figure out Parse Hosting - Cloud Code Integration

I've been working on this seemingly simple problem for about a week now and feel like there is conflicting information and am hoping someone can give shed some light for me. I'm trying to use Parse Hosting for a marketing site with bootstrap, just HTML and CSS with a little JS; and Cloud Code to do some simple server side tasks like charging a card via Stripe. Everything in the documentation makes it seem this is easily doable, but the documentation also seems to lead me to believe certain methods aren't.
For example, this video shows a Stripe engineer building exactly what I want. However, it's not abundantly clear that he is using pure HTML and CSS for the front end instead of an Express templating engine (which I am not using) - http://blog.parse.com/videos/parse-developer-day-2013-a-new-kind-of-checkout/
This post says Parse Hosting and Express now work hand in hand, GREAT!
http://blog.parse.com/announcements/building-parse-web-apps-with-the-express-web-framework/
But the documentation (JS > Cloud Hosting > Dynamic Websites) says you have to delete index.html >> "If you choose to use Express or Node.js, you'll first need to delete public/index.html so that requests can get through to your custom handler functions."
I want to have a single page website hosted at public/index.html that uses Stripe Checkout v3 to create a token then pass that to Parse for a quick execution of the charge, but again, every which way I try has been unsuccessful so far.
In addition, I'm thinking Parse Hosting of pure HTML/CSS won't work with Cloud Code the way I want because a simple call of /hello below returns nothing.
Here's my code:
//public
//index.html
<form action="/charge" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="pk_test_zippitydoo"
data-image="http://image.jpg"
data-name="Thing"
data-description="Shut up and take my money"
data-amount="4000">
</script>
</form>
//cloud
//main.js
var express = require('express');
var app = express();
var Stripe = require('stripe');
Stripe.initialize('sk_test_blahblahblah');
app.get('/hello', function(req, res) {
res.send('hello world');
});
app.post('/charge', function(req, res) {
res.send('Charge Attempt');
token_id = req.body.stripe_token
Stripe.Tokens.retrieve(token_id).then(function(token) {
return Stripe.Charges.create({
amount: 1000,
currency: "usd",
source: token_id
});
});
});
What you need is for express to serve your HTML. To do this, register a static resources directory. In your main.js, after you instantiate your app with var app = express(), do this:
app.use(express.static('public'));
Express should then treat your /public/index.html file as the directory index by default, and your app will serve any other files under /public. More info: http://expressjs.com/4x/api.html#express.static
There are several things I did wrong here. I'll explain my mistakes, then you can compare the below code that works with the above code in the question that doesn't.
1) I wasn't parsing the data I was receiving (see underneath // App configuration section)
2) The JSON that is passed needs to be parsed using CamelCase (stripeToken not stripe_token)
3) The charge is set as a variable, not returned (var = charge instead of return charge). Return may work, I didn't test it however.
4) It is imperative that you include the app.listen(); in order to connect to the public folder from the cloud folder
//cloud
//main.js
var express = require('express');
var Stripe = require('stripe');
Stripe.initialize('sk_test_blahblahblah');
var app = express();
// App configuration section
app.use(express.bodyParser()); // Middleware for reading request body
app.post('/charge', function(req, res) {
var stripeToken = req.body.stripeToken;
var stripeEmail = req.body.stripeEmail;
res.send('Charging your card...');
var charge = Stripe.Charges.create({
amount: price,
currency: "usd",
source: stripeToken,
receipt_email: stripeEmail
}, function(err, charge) {
if (err && err.type === 'StripeCardError') {
res.send('The card has been declined. Please check your card and try again.');
}
});
});
// Attach the Express app to your Cloud Code
app.listen();