Originally posted on my blog

These days it’s common to encounter someone asking questions like the following:

  • Why did I write Vue application in the development stage is ok, after deployment to the server can not access except/The page?
  • Why I wrote the SPA page routing using hash mode is ok, change the history mode is problematic
  • What is front-end routing and what is back-end routing? How do I configure the back-end to support my front-end routing

This question is a lot of beginners will ask questions, so combined with my own learning experience to briefly explain the difference and connection between the two, I hope to help you.

Old hands can take a detour to read more useful articles

What is routing

Understanding Web routing is a particularly good article.

In Web development, the concept of “routing” is often encountered. So what exactly is routing? Simply put, routing is a mapping of URLS to functions.

The URL is mapped to the corresponding function (which is generalized and can be a front-end or back-end function), and the corresponding function decides what to return to the URL. Routing is doing a matching job.

Start with back-end routing

Back in the “slash-and-burn” days of the early days of Web development, back-end routing dominated. Whether it is PHP, JSP, ASP, the user can access to the page through the URL, mostly through the backend route matching and then returned to the browser. The classic interview question, “What happened to you between typing www.baidu.com into the browser’s address bar and seeing the web page”, does the same thing.

On the Web backend, no matter what language the backend framework is, there is a dedicated routing module or routing area that matches the URL address given by the user, as well as the address of some form submission and Ajax request. When a route is not matched, the back end will return a 404 status code. This is why we say 404 NOT FOUND.

The URL and the Methods

If you follow RESTful apis, you’ll be familiar with the following four types of request initiation: GET, POST, PUT, and DELETE.

They correspond to four basic operations: GET to obtain resources, POST to create resources (which can also be used to update resources), PUT to update resources, and DELETE to DELETE resources. — Ruan Yifeng, Understanding RESTful Architecture

Although RESTful apis are mentioned above, when we type a URL into the address bar and enter, we send it as a GET request. This also shows that the URL address and the request method should be one-to-one correspondence. Here’s an example:

router.post('/user/:id', addUser)
Copy the code

Suppose this is the only route in my back-end route configuration. If I visit http://xxx.com/user/123 in my browser, it will not be accessible and will return a 404. Because the backend is configured with only one POST route. To accept this request, you must have the following route:

router.get('/user/:id', getUser) // Configure the GET route
router.post('/user/:id', addUser)
Copy the code

Back-end routing and server rendering

As mentioned earlier, in the slash-and-burn era, web pages were often routed directly to the client browser via back-end routing. The HTML of a web page is rendered by a template engine on a back-end server and handed to the front end. Other effects are handled through jQuery, Bootstrap, and other common front-end frameworks written in the page.

If you say that some websites are already ajax pages, such as Gmail, such as QQ mail. Notice that even these pages, their keel is not entirely Ajax, and they’re still straight out of the back end — the old server-side rendering we’re talking about.

There are many benefits to server-side rendering, such as SEO friendly, some pages with high security requirements are safer to use server-side rendering. At that time before Node.js, in order to build front-end pages well, dynamic web pages, page structure organization and component reuse were realized through the template engine corresponding to the server language. Laravel blades, Jinja2 for Django, JSPS for Struts, etc. In fact, to this day and age, a back-end language needs its own template engine to implement its own Web functionality.

With node.js, a front-end template engine with its own back-end rendering has become a reality. Common ones are PUg, EJS, Nunjucks, etc. These template engines paired with back-end frameworks such as Express and Koa were also popular in the beginning.

However, in this process, as the development of Web applications became more and more complex, the problems of simple server rendering began to be slowly exposed — the coupling is too strong, the pages in the era of jQuery are not easy to maintain, the page switch is serious, etc. Coupling problems can be solved with good code structure and specification, but pages in the jQuery era are notoriously difficult to maintain, with global variables flying around and code being too intrusive. Subsequent maintenance usually involves patching the previous code. The problem of a white screen for page switching can be solved with Ajax, iframe, etc., but it is difficult to implement — making it more difficult to maintain.

So, we entered the era of front-end routing.

Transition to front-end routing

Front-end routing – As the name implies, the front end controls the matching of URL rules for page jumps. Front-end routes are displayed in two modes:

  • Front-end routes with hash features high compatibility. The disadvantage is that the URL has#Don’t look good,
  • The advantage of the front-end route without hash is that the URL is not included#Size, nice. The disadvantage is that both browser support and back-end server support are required

The most widely used example of front-end routing is today’s SPA Web project. Whether it is Vue, React, or Angular page engineering, it is necessary to have the corresponding router tool. The most obvious benefit of front-end routing is that URL jumps to the address bar are no longer blank – thanks to the benefits of front-end rendering as well.

Front-end routing and front-end rendering

We can’t talk about front-end routing without talking about front-end rendering. I take the Vue project as an example. If you’re building your project using the official VUe-CLI with webPack templates, have you ever wondered what HTML your browser will get? Does your page look like a button and a form? I don’t think so. In production mode, you can see what the constructed index.html looks like:


      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue</title>
</head>
<body>
  <div id="app"></div>
  <script type="text/javascript" src="xxxx.xxx.js"></script>
  <script type="text/javascript" src="yyyy.yyy.js"></script>
  <script type="text/javascript" src="zzzz.zzz.js"></script>
</body>
</html>
Copy the code

It usually looks like this. As you can see, this is actually the HTML that your browser gets from the server. All that’s left is a div with a

entry and a set of js files below. So the page you see is actually rendered with those JS. This is also what we call front-end rendering.

Front-end rendering gives the task of rendering to the browser and solves the problem of page construction through the computing power of the client, which greatly relieves the pressure on the server side. And with front-end routing, the seamless page switching experience is naturally user-friendly. The downside, however, is that it’s not SEO friendly, because search engine crawlers can only crawl the ABOVE HTML, and the browser version will have corresponding requirements.

To be clear, any time you type the URL in the browser’s address bar and press Enter, you will definitely make a request to the backend server. URL updates made using the Router library API will not be requested by the backend server if they are performed on a page by clicking a button, etc.

Hash pattern

The hash mode takes advantage of the fact that the browser will not make a routing request to the server on the path following the #. In other words, enter http://localhost/#/user/1 and http://localhost/ in the browser to request the contents of the http://localhost page.

The front-end router library tells the front-end library (such as Vue) to render the corresponding page by capturing the parameters and addresses after the # sign. In this way, the jump logic is the same whether we type in the browser’s address bar or jump to a page using the Router’s API. Therefore, this mode does not require the back-end to configure other logic, as long as the front end to return the corresponding HTML http://localhost, the rest of the specific page, by the front end to determine the route.

The History mode

The route without # is the URL form we usually see. Router libraries typically do this through the HISTORY API provided by HTML5. For example, history.pushState() pushes a URL to the browser’s address bar, but that URL doesn’t make a request to the back end! This feature makes it easy to implement nice urls. Note, however, that this API is not supported for IE9 and below, IE10 is supported, so there are requirements for browser versions. Vue-router detects the browser version and demotes the browser to hash mode if history mode cannot be enabled.

The router API calls history.pushState(), so it has nothing to do with the back end. But once you type an address from the browser’s address bar, such as http://localhost/user/1, the URL initiates a get request to the back end. If there is no route configured in the back-end routing table, it will return a 404. This is why many of your friends encounter 404 pages in production mode.

So a lot of people ask, why am I ok in development mode? That’s because the Express development server that vue-CLI starts for you in development mode does this for you. In theory, you would have to configure the server in development mode, but vue-CLI does it for you, so you don’t have to do it manually.

So how do you configure it? The configuration in production mode is also very simple. For details, see vue-router configuration example. One rule is to configure a rule at the end of all back-end routing rules that will be executed if none of the previous routing rules match – returning the constructed index.html to the front end. This fixes the 404 thrown by the back end route, because if you type http://localhost/user/1, it will be returned to the browser index.html because none of the other back end routes match.

Once the browser gets the HTML, the Router library goes to work, fetching the URL information from the address bar and telling the front-end library (such as Vue) to render the corresponding page. At this point, it’s similar to the hash pattern.

Of course, since the back end cannot throw 404 page errors, the 404 URL rules are left up to the front end. You can decide for yourself in the front-end routing what should be displayed on any 404 page with a mismatched URL.

Front-end routing and server rendering

Although front-end rendering has many benefits, the SEO issue is still quite prominent. React, Vue and other frameworks also made their own efforts in server rendering. Server-side rendering based on front-end libraries is different from previous server-side rendering based on back-end languages. Server-side rendering of front-end frameworks still mostly uses front-end routing, and due to the introduction of concepts such as state unification and VNode, their server-side rendering requirements on server performance are much higher than the string-filled template engine rendering based on PHP and other languages. In this respect, not only the framework itself is constantly improving the algorithm and optimization, but also the performance of the server side must be improved. That’s why the Nuggets had performance issues when they switched to SSR.

In between, of course, comes the concept of pre-rendering. That is, a static HTML file is built on the server side to be used directly out of the browser. The rest of the page is then rendered using the usual front-end rendering. Usually we can use a pre-rendered home page. The benefits of this are obvious, both in terms of SEO and server performance. However, it will not be able to achieve full site SEO, and the production build phase will take longer, which is also a pity.

For pre-rendering, consider the prerender-spa-plugin for Webapck, whose 3.x version starts using Puppeteer to build HTML files.

Front end separation

Thanks to front-end routing and the full front-end rendering capabilities of modern front-end frameworks, everything related to page rendering, organization, and components can finally be removed from the back end.

The development mode of separating the front and back ends is also gaining popularity. The front end began to pay more attention to the engineering and automation of page development, and the back end is more focused on the provision of API and database protection. At the code level, the coupling degree is further reduced and the division of labor is more clear. We’ve moved on from the slash-and-burn era of Web development. Then take ~

conclusion

Hopefully this article will give you an understanding of both front-end routing and front-end rendering. In the actual development process, you should not only focus on your own field, but also dabble in related fields, so that you can deal with problems with ease.

Note: I used OmniGraffle to create the images in this article. Reprint please indicate the author!