• Skip to main content
  • Skip to footer

InRhythm

Your partners in accelerated digital transformation

  • Who We Are
  • Our Work
  • Our Culture
  • Events
  • Testimonials
  • Blog
  • Contact Us

Matt Billard

Dec 21 2020

Lightning Talk: Creating a Proxy with Node + Express

tldr;

I created a Node and Express proxy that rams together two websites / apps. If you are ever asked to develop code for a site you don’t have access to, this could save the day.

  1. Download the code:
    https://github.com/mattbillard/code-collider-v2
  2. Watch the video:

My most recent hobby project involved building a Node and Express proxy to ram two websites or apps together. I dubbed it “The Code Collider.” 

The idea of the Code Collider was born about two years ago when I was given a rather difficult coding challenge at a client. Another department had a website and we were being asked to iframe it. As you might know, iframes have a lot of “interesting nuances” as they might politely be called, one of which is that if a user right-clicks on a link and chooses “Open in new tab,” they will break out of the parent’s iframe and go directly to the iframed child site. Of all things, I was asked to write some code to prevent this and provide my solution to the other team. There was just one catch: I had no way of running the other team’s site in my local environment and thus (or so I initially thought) no easy way to test my code as I wrote it. 

This situation comes up more often than you’d think. There are several reasons a developer might not be able to run a site or app in their local environment. Perhaps it’s complex to set up, involves a lot of permissions, or the other team just can’t be bothered to spare the time to help you out. Regardless of the reason, I did eventually strike upon a novel way to solve the problem.

After what felt like a meandering odyssey of Stack Overflow posts, I managed to cobble together a Node and Express project that took the other team’s site, piped it through a proxy, injected my script into it, and served it to my browser. Even though my innovation worked and I was able to deliver the final code requested, there was just one thing that bothered me: I always had the nagging feeling that I had only gotten the proxy to work through a mixture of stubborn persistence and blind luck. I resolved to rebuild it from scratch in my free time one day, piece by piece, actually understanding how the solution worked – and that as it turns out is exactly what I did.

The Architecture

Here’s a diagram of how it works:

The browser makes a request to our Node Express proxy server where we then have three scenarios:

  1. If the user requested an HTML page, we need to combine the page from website 1 and 2. The proxy first asks website 1 and then website 2 for its HTML. It then modifies the two HTML files, combines them, and returns the result to the browser. (Details on how this works below.)
  2. The HTML page will then request the CSS, JavaScript, and other assets it requires. These requests will again go through the proxy which will pass on the requests. If website 1 has the asset, great, the proxy will return it to the browser. 
  3. If website 1 does not have the asset, the proxy will then ask website 2 and return it to the browser.

Here are screenshots of the result:

In this example, we’ll use the real InRhythm.com website as the target into which we’ll inject some local code (in this case a basic Create React App project). The final result on the right is an actual screenshot of the 2 websites living together in the same browser window. Now this is pretty exciting; the target website and the code that you are developing could be anything!

How it Works

  1. As mentioned above, website 1 and 2’s HTML are combined. This involves a few steps. Webpages can’t have 2 doctype, html, head, or body tags, so we’ll use some regex to strip those. Now that website 2’s HTML is ready, we’ll inject it before website 1’s closing </body> tag. 
  1. And here is the code that shows our modifications to website 1’s HTML. It shows a few things.

    Firstly, many websites have full ‘absolute URLs’ for their links. They look like this: https://www.inrhythm.com/who-we-are/
    The problem is if the user clicks on this, they’ll be taken away from our proxy and go to the target website. We’ll solve this by removing all www.something.com bit and keep just the bit after the slash.

    Secondly, we show injecting the CSS discussed above to remove backgrounds and allow clicks to pass through website 2 to website 1. (Keep in mind this will probably be slightly different depending on the two sites you are combining.)

    Thirdly, we show injecting the HTML from website 2 we modified from above before the closing </body> tag.

Gotchas to Avoid

As mentioned above, it took a lot of research as well as trial and error to solve all the technical hurdles this project presented. Here are some of the main ones below.

  1. Websites usually compress or “Gzip” their content. Normally this is a great thing. It means less data is transferred and websites load more quickly. This is not going to work for our case however. You can’t parse, manipulate, and modify HTML if it looks like gibberish. The solution was actually quite simple: as it turns out, there’s a header you can send with your request to ask the server not to Gzip anything.
  1. There’s another header we need to send however. Because we’re using a proxy, all requests are going to have the header ‘host’ set to ‘localhost’. Now this is probably not a problem for most sites, but to the target server, this doesn’t look like a very normal request, and indeed, I did find some websites responded oddly and returned pages that looked nothing like I expected. The solution again was quite simple, just modify one of the headers of our request. 
  1. Now as you’ve probably gathered from above, we’ve modified our requests quite a lot, and as a result this is going to cause the browser to do some odd things. The solution to this problem is to delete the ‘content-length’ header before the proxy sends your browser any response. This will stop the browser from truncating the response and removing all the hard work we did. 
  1. Finally, I’ll mention one other problem I solved. If you are combining sites that use https, the proxy might complain that the SSL certificates don’t match what it’s expecting. Turns out it’s rather easy to relax this with the following code: 

Conclusion

That’s it. Feel free to download the code, follow the instructions in the readme, and open your browser to localhost:8000 . You should be able to see two web sites rammed together. 

Written by Matt Billard · Categorized: Cloud Engineering, InRhythmU, Learning and Development, Web Engineering · Tagged: express, Node.js, proxy

Jul 13 2017

Comparing Angular 2 vs React vs Vue

InRhythm recently hosted our second Code Lounge, where I discussed the differences between Angular 2, React+Redux and Vue+Veux. The 60 attendees proved to be a solid sounding board for the discussion and below is a summary of my findings shared with the group.

Whenever I start a new project, I’m always faced with the challenging question: “what should I build it in”? Research is important, but sometimes it feels like comparing apples to oranges. How can you compare a library (React) to a framework (Angular)? I’ve found that the best approach is to build something simple in each one and compare the experience. To share with my fellow developers, I’ve built an application to compare existing JavaScript solutions – Angular 2, React+Redux and Vue+Veux.

For simplicity’s sake, I made a list of “blog articles”, with create, read, update, and delete (CRUD) functionality to create more of an “apples-to-apples” comparison. Please note that my opinions are based on working with the three tech stacks for a few weeks and I respect any differing opinions of other developers on this subject.

Comparison Summary

Angular2

PROS CONS
  • A complete solution
  • Class syntax: makes the code very well organized
  • TypeScript

 

 

 

 

 

 

  • Too much has changed
  • Very steep learning curve
  • It’s not plain JS: difficult to migrate to other frameworks or upgrade to Angular2
  • Somewhat verbose: every file needs tons of import statements
  • Angular2 syntax: not as simple as Angular1. ng-____ was so much simpler.
  • TypeScript
  • Errors aren’t helpful at all
  • Huge build: Angular2’s production build is 3 to 5 times as big as the other solutions!

Honestly, the more I work with other solutions, the harder it gets to say a lot of positive things about Angular2. A complete solution initially seems like a huge benefit, but then you are then required to use everything they recommend, nothing more, nothing less. Similarly, TypeScript feels like a plus with it’s strong types, error checking, and clear interfaces, but is difficult to learn to set up. There seem to be few resources out there to show you how to add typings to your project, and not all IDE’s seem to support it well.

Far too much changed between Angular1 and 2. The HTML templating syntax was the least of it. They added TypeScript, both SystemJS and Webpack, Rx.js, and replaced promises with observables and the learning curve is very heavy. Also, because Angular has it’s own special version of everything (e.g. $http, $q, etc) it is extremely difficult to migrate existing projects. Everything needs to be rewritten.

React+Redux

PROS CONS
  • Mobile
  • Server-side rendering
  • Immutable Data
  • Complexity
  • No standard technologies
  • JSX syntax: can be complicated. It’s far simpler to use HTML and Angular1 or Vue syntax

React seems to have a few very clear advantages. If you need to make a mobile app, or if search engine optimization (SEO) is a high priority, React has the oldest and most mature solutions.

Implementing delete operation for our CRUD app was by far the most complex in React+Redux, requiring 13 pieces of code strewn across 7 files. Standardization is also a challenge. While Angular is strict with it’s recommendations, React is loose. Some developers feel it is better to have more choices, but I feel the opposite. React technologies seem to change often. Flux has been replaced by Redux. Redux seems like it’s going to be replaced by MobX. The examples I found used Thunks. I’m told that Saga is a better (and more complicated) solution. Researching, learning, comparing, and vetting the myriad choices is very time consuming. Especially in a large corporation with many teams in many countries, standardization (having a “right way”) would be a huge time saver.

Vue+Vuex

PROS CONS
  • Angular1’s syntax: v-for, v-if, v-model, v-class, etc
  • React’s speed and size
  • Redux’s state management: single store, immutable state
  • Great CLI: Vue, router, Webpack, HMR, eslint, tests
  • Simplicity
  • Recommendations but not too opinionated: Angular2 often seems too rigid while React has the opposite extreme: you need to figure out all the pieces you want to use for your solution. Vue seems to take the middle road: it recommends a complete solution but ultimately lets you pick the pieces you want to use. Better yet, you can scaffold out a new project with a single line in the terminal.
  • Code style: linting rules are a little weird. It prefers no semicolons and adds spaces in some weird places.
  • No classes: I liked Angular2’s classes, but I guess I can live without them

 

 

 

 

 

It appears to me that someone compiled the best parts of the competing solutions!

Numerical Comparison

Size and speed (load + render time) of built code

Angular2 is by far the largest. React+Redux and Vue+Vuex are similar.

  • Angular2: 1,500 kb, 1.5 seconds!
  • React+Redux: 200 kb, 0.6 seconds
  • Vue+Vuex: 400 kb, 0.6 seconds

Complexity of adding delete functionality to our CRUD app

React was by far the most complicated. Angular2 and Vue+Vuex are similar.

  • Angular2: 3 blocks of code in 3 files
  • React+Redux: 13 blocks of code in 7 files!
  • Vue+Vuex: 3 blocks of code in 3 files

Installing Dependencies and Running the Projects

You will need to install and then run all 3 of the following to try the different solutions.

Server

This is a simple Express server for our articles api to which we can make get, post, put, and delete requests.

Run the following:

cd server-api && npm install && npm start

Angular2

The original code was taken from the Angular2 “Tour of Heroes” app in the official documentation: I modified the code into a simple CRUD form for a blog and swapped SystemJS for Angular2 Webpack.

Run the following:

cd angular2 && npm install typescript tslint -g && npm install && npm start

 

Build:

 npm install http-server -g && npm run build http-server ./dist

React+Redux

The original code was taken from the best React+Redux tutorial I could find: “Building Applications with React and Redux in ES6” by Cory House (Corey’s very good. I highly recommend you watch it.) Once again, I changed it into a simple CRUD form for a blog.

Run the following:

cd react-redux && npm install && npm start

 

Build:

npm run build

Vue.js+Vuex

Vue CLI’s command “vue init webpack PROJECT_NAME” was used. Then I built the CRUD app from scratch.

Run the following:

cd vue-vuex && npm install && npm start

 

Build:

npm run build http-server ./dist

 

Learning More

There’s a lot to learn with each solution! Please click here to review more resources and tips around this subject.

Written by Matt Billard · Categorized: Agile & Lean, Bootcamp, InRhythm News

Footer

Interested in learning more?
Connect with Us
InRhythm

140 Broadway
Suite 2270
New York, NY 10005

1 800 683 7813
get@inrhythm.com

Copyright © 2021 · InRhythm on Genesis Framework · WordPress · Log in

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPT
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.

Necessary Always Enabled

Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.

Non-necessary

Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.