Server side response to allow client side routing - node.js

I am developing a single page application that has a client side router. so although the base url to run the application will be either http:://example.com or http:://example.com/index.html - skipping the domain name that is routes '/' and '/index.html'
But somewhere in my application, because of my client side router, I may call up a route something like '/appointments/20160113 and the client router will redirect me to the appropriate "Appointments Page" inside my SPA passing the parameter of todays date.
But if the user calls directly http://example.com/appointments/20160113, I am led to believe that the server should respond directly with /index.html so the browser doesn't get a 404.
I am building the server using nodejs (specifically the http2 module, but I don't think that is very important, and my examples don't use https, although with http2 they do). I just tried changing the server so if its hit with an unknown url it responds with the index.html file.
However, the browser sees this as its first response and then makes requests for the rest of its attached files relative to the url (so for instance follows up with /appointments/20160113/styles/main.css). This leads to an infinite loop, as the server responds with another copy in index.html (and immediately gets a request back for /appointments/20160113/styles/styles/main.css ).
Its too early in the lifecycle of the page for the javascript to be running yet (and specifically the router software), so clearly the approach is too simplistic.
I have also written the client side router (using the history api) so I can change things if I need to.
How should this situation be handled. I am thinking perhaps a 301 redirect to /index.html or something and then the router's initial dispatch knows this and can do a popstate or something. I ideally want to support the passing of urls via external means between users, but until I actually tried to implement it I hadn't realise the implications.

I don't know if this is the best way or not, but having not received any answers on here, I decided to try a number of different ways and see which worked out the best.
Each way involved doing a 301 redirect to /index.html, and then providing the url from which I was redirecting via different mechanisms
This is what I tried
Setting a cookie with a short expiry date the value of which was the url
Adding a query string with a ?redirect= parameter with the url
Adding a #fragment after /index.html with the url
In the end I rejected 1) because chrome wasn't deleting the cookie after I had used it and making the value shorted lived depends on accurate timing between client and server. The solution appeared too fragile.
I tried 2) and it was looking good until I came to test it. Unfortunately setting window.location.search causes a page reload, and I was really struggling with finding out what was happening. However, what I discovered in 3) about mocking could well be provided to a solution based on 2) so it is one that could be used. I still might return to this solution as it "feels" right to me.
I tried 3) and it worked quite well. However I was struggling with timing issues in testing since my router element was using the #fragment during initialisation, but I couldn't set the window.location.hash until after the router was established in the test suite. I wanted to mock window.location.hash with sinon so I could control it, but it turns out you can't
The solution to this was for the router to wrap its own calls to window.location.hash in a library, so that I could mock the library. And that is what I did in the end and it all worked.
I could go back to using a query string and wrapping window.location.search in a library call, so I could stub that call and avoid the problems of page reloading.

Related

https server is listening and executes functions even when the url is only suggested, but not confirmed

I am building a simple text adventure game in Nodejs. So I noticed that the server.js is listening to the suggestions that come up in the address bar and then executes functions relevant to those suggestions without me actually going to that url. This is weird because I do have return res.end() in each endpoint.
It is messing up my program.
What do I do?
If the HTTP method is GET, then the browser is free to predict and pre-fetch the content. This is because the HTTP semantics of GET is that it should not change server state. If you are trying to make use of requests that might mess up your server state, then make them POST requests and issue the requests from the JavaScript of your page. POST has the semantics that it may change server state and therefore the browser will not make the request without you explicitly doing so from JavaScript.

Express response interception. Use body to modify the outgoing headers

I would like to try and improve site render times by making use of preload/push headers.
We have various assets which are required up front that I would like to preload, and various assets which are marked up in data attributes etc which will be required later via JS but not for initial paint. It would be good to get these flowing to the client early.
Our application is a bit of a hybrid, it uses http-proxy-middleware connected to various different applications, plus directly renders pages it self. I would like the middleware to be agnostic and work regardless of how to page is produced.
I've seen express-mung but this doesn't hold back the header so executes too late, and works with chunked buffers anyway not the entire response. Next up was express-interceptor, that works perfectly for pages rendered directly in express but causes request failures for pages run through the proxy. My next best idea is pulling apart the compression module to figure out how it works.
Does anyone have a better suggestion, or even better know of a working module for this kind of thing?
Thanks.

Refreshing with Browser History using React Router returns calls from my API

From what I understand, to use the browserHistory object in React Router properly, we need to use a wildcard * route so that the user is returned the single page application upon every refresh. Where this becomes a problem is when my client-side URL is the same as one of my api URLs.
For example, say I have a website called example.com and that one of the pages on this site is example.com/profile. If I refresh, the expected behavior is that it will simply reload the website example.com and route correctly to /profile, since the wildcard route should have returned the client the single page application. Where this doesn't work is if I have an API route /profile, i.e. example.com/profile. Now when the user refreshes the page, instead of being returned the the profile page, they are instead returned a JSON response from my API.
Depending on the order in which the wildcard route is declared, I can either have the API response returned on refresh, or the single page app on refresh, but not both when the API url is the same as the client side browser url.
Are there any suggestions around this issue? My current solution is to migrate all of my API routes to have /api/ prepended to them.
You need to make sure your client routes do not collide with your API routes, and prefixing API routes with /api is a pretty standard way to handle this.
There's no real way "around" the issue other than making sure they don't collide – various workarounds might be possible, but it's going to be more clear for everyone involved if routes are unambiguous.

Modifying content delivered by node-http-proxy

Due to some limitations about the web services I am proxying, I have to inject some JS code so that it allows the iframe to access the parent window and perform some actions.
I have built a proxy system with node-http-proxy which works pretty nicely. However I have spent unmeasurable hours trying to modify the content (on my own, using harmon as well, etc) that is being sent to the user without any success. I have found some articles and even some questions here but all of them are outdated and are not useful anymore.
I was wondering if someone can give me an actual example about how to do this, because I am unable to do it and maybe it is just that it is impossible to do at this point?
I haven't tried harmon, but I did try cheerio and it works.
However, I used http-mitm-proxy and not node-http-proxy.
If you are using http-mitm-proxy, you need to return a promise in the response handler. Otherwise, the proxy continues to send the original response without picking up your changes.
I have recently written another proxy at:
https://github.com/noeltimothy/noelsproxy
I'm going to add response handling to this soon. This one uses a callback mechanism, which means it wont return the response until the caller signals it to.
You should be able to use 'cheerio' and alter the content in JQuery style.

Express & Backbone Integration

Ok, I am new to web dev and here's a stupid question. I have been through a few tutorials for node, express and backbone individually, but I can't seem to wrap my head around how they are integrated. Particularly, consider this use case:
Person X opens the browser, types in a URL and hits enter->Express responds to the request and sends some data back to the browser.
My question is, where does backbone come into the picture here ? I know it's a mvc framework to organize your JS code. But, I can't find a place in this use-case where the server/browser interacts with backbone. Only thing I can think of is that the backbone saving the route and serving the page the next time. But what about the first time ? It would be best if someone could explain to me how the request gets routed from client browser to express/backbone to browser again.
Also, am I correct in assuming response.send() or response.json() will send the result to backbone when model.fetch() is called ? I mean, is there no additional code required ? Being new to web dev, I'm quite not used to the idea of the framework 'taking care' of everything once you send the response back.
EDIT : Here's what I have understood so far. Feel free to correct me if I am wrong. When I access websites like gmail, the server first sends a big html file including backbone.js code in it. The backbone.js code listens for events like clicking on links in the html file and handles them if the links are defined in it routes(routes are always relative to current route, accessing a completely different route sends request to the server). So, if I click compose, my url remains the same because backbone handles the request. However, if I click Maps/News services in the bar above, the server handles the request.
There is no special integration between backbone and node.js.
If you use the standard backbone sync method then all you need to do is:
Use the static middleware in express to serve up your static html/js/... files.
Define RESTfule routes in express that conform to what backbone is expecting.
Backbone does indeed make an http call when you do model.fetch. You could look in Chome network tab to see where it's sending the request to and then implement that route in express.

Resources