This is the first day of my participation in the August Challenge. For details, see:August is more challenging

SSR stands for server side rendering. Before the front-end was popular, the previous website was to concatenate HTML strings on the server side and return them to render on the page. Vue SSR do is in the page request url, will get back from the service side rendering a good rendering HTML string, the first screen data needed for an asynchronous request, fill to the front-end display, rather than a joke, SSR is a code to run in two environments (server and client), the server to run, The template is rendered into HTML page, and then returned to the front end, and then the front end loads JS file to complete activation. The subsequent operation is SPA, so that the first page is rendered by the server side with data, and the SEO crawler can obtain data. At the same time, because the first screen only renders a page, the subsequent activation of SPA takes place in the browser side. The first screen rendering issue has also been resolved.

Disadvantages of Vue SSR: it is complicated in the configuration process, two entry files need to be configured, one is required for the first screen rendering of the server, the second is required for the front-end activation, nuxT.js makes it easier to implement SSR

Compared with simple SPA, server-side rendering increases the burden on the server. When the number of users is large, because new VUE instances need to be created at the back end, performance is wasted compared to simple data request. While Vue’s server-side rendering (SSR) is fairly fast, the overhead of creating component instances and virtual DOM nodes does not match the performance of a pure string concatenation based template. In situations where SSR performance is critical, a judiciously used caching strategy can greatly improve response times and reduce server load to cache component page interfaces.

Front and back end isomorphism, back end needs to write front-end Vue code, contrary to the separation of front and back end, this can be achieved through WebPack packaging, only need to configure entry file and the corresponding logic can be.

Caching and o&M issues.

Application scenario: not all websites need SEO, such as enterprise internal website, day after tomorrow management system, etc. Some old vUE projects, the cost of refactoring is too big, the first screen rendering can be lazy route loading, load on demand mode, modify the corresponding problem, not completely pull down the rewrite. Before the server returns the result, processing can be done to determine whether it is a crawler, to decide to pre-render

Application scenarios of SSR

1. SEO needs

SEO (Search Engine Optimization, Search Engine Optimization), is a kind of use of Search Engine rules, improve the site in the Search Engine natural ranking technology. Usually this requires that the page content is already there when the page has finished loading. The existence of SEO demand is inseparable from the development course of Internet technology. In the early days of the Internet, web pages used hypertext link protocol to transfer information from servers to clients. Then came the search engines that retrieved information specifically for people. With the continuous development of front-end technology, there are pure front-end projects that are separated from the front and back ends. Since this kind of project needs to asynchronously obtain data rendering after the page is loaded, most search engines cannot obtain the content of this kind of project. Vue SSR is a technical solution based on such requirements. Nodejs is used to build the page rendering service, and the page rendering work that needs to be completed on the client before the server is completed is output to the SEO more friendly page.

In addition to the Vue SSR scheme, you can also select Prerender (github.com/prerender/p… The same thing about SSR is that the Prerender uses Phantomjs, a no-interface virtual browser, to render the output page, whereas Vue SSR is based on the Vue component. Prerender is more generic and can be used on any page, whereas Vue SSR can only be used on Vue projects, but because Vue SSR is direct rendering at the code level, it does not need to pull static resources as Prerender does, so it is faster.

As to which technical solution should be used, it depends on the needs and actual conditions.

2. First screen rendering speed

As mentioned in the above SEO requirements, the current front-end project separated from the front and back ends needs to load static resources first, then obtain data asynchronously, and finally render the page. In this process, the first two pages have no data, which affects the rendering speed of the first screen, and also affects the user experience. There are a number of schemes to improve the speed of first screen rendering, in addition to SSR, keel, gravestone, and data straight out. Compared with these schemes, SSR scheme is the most complex to implement, but also the best effect.

3. Selection of Vue SSR scheme

At present, there are two implementations of Vue SSR, one is the official scheme based on the official Vue SSR guide document, and the other is the vue.js general application framework -NUXT. The official solution has a more direct control over the structure of the application, deeper and more flexible, and in the process of using the official solution, a deeper understanding of Vue SSR will also be gained. NUXT offers a smooth out-of-the-box experience that builds on the same Vue technology stack, but abstruses many of the templates and provides additional features such as static site generation. Through NUXT, Vue SSR can be quickly implemented according to the agreed rules.

Some problems that are easy to encounter in development

1. Two execution environments for one set of code

In vue’s lifecycle hook functions, only beforeCreate and Created are called during the server rendering (SSR) process. This means that the code in these two hooks and the global code except for vue’s lifecycle hook functions will be executed in both the server and client environments. If you add code with side effects or access to platform-specific apis into the code for both environments, problems can arise. For example, if the server does not have a window or document object, adding references to or operations on this object will cause an error on the server.

Therefore, in summary, the most common mistake to make is to use window or document objects without judging the context.

Solution:

(1) In beforeCreate, created life cycle and global execution environment before calling a specific API need to judge the execution environment;

(2) Use adapter mode, write a set of adapter compatible with different environment API.

2. Data is pre-obtained from the server

The official solution uses Vuex to pre-obtain data on the server. Add the Vue hook function on the server, get the data, save it in the Store structure of VUEX, and render the page at the same time.

In the hook functions registered during the data prefetch phase, it is best to only fetch and save data, and not do any other operations involving this. Because this is the server’s this, which is shared by all users, some unexpected errors will occur.

For example, you might want to manipulate data in a hook function that prefetches the data. First, the data prefetch hook function doesn’t have an instance of Vue at runtime, so it can’t get anything about that instance at all. Secondly, the access operation is carried out under the public variable of all users. Once the access operation is successfully carried out, it must be the access operation of all users.

At the same time, it should be noted that vuEX should use lazy registration scheme under Vue SSR scheme. If you do not use the lazy registration scheme, and instead register all modules uniformly when vuex initializes the instance in the first place, you will have the problem of multiple pages sharing many modules.

If we have the store module as follows:

 1 // store/modules/foo.js
 2 export default {
 3  namespaced: true.4  // Important information: state must be a function,
 5  // So you can create multiple instantiations of the module
 6  state: () = > ({
 7    count: 0
 8  }),
 9  actions: {
10    inc: ({ commit }) = > commit('inc')
11  },
12  mutations: {
13    inc: state= > state.count++
14  }
15 }
Copy the code

In the routing component, you need to lazily register the VUEX module as follows

 1 // Within the routing component
 2 <template>
 3  <div>{{ fooCount }}</div>
 4 </template>
 5 <script>
 6 // Import the module here, not in 'store/index.js'
 7 import fooStoreModule from '.. /store/modules/foo'
 8 export default {
 9  // The data prefetch lifecycle runs on the server
10  asyncData ({ store }) {
11    // Lazily register the Store module
12    store.registerModule('foo', fooStoreModule)
13    // Perform an action named inc in the foo namespace
14    return store.dispatch('foo/inc')
15  },
16  // Important information: When the route is accessed multiple times,
17  // Avoid registering modules twice on the client.
18  destroyed () {
19    this.$store.unregisterModule('foo')
20  },
21  computed: {
22    fooCount () {
23      // Obtain the store data
24      return this.$store.state.foo.count
25    }
26  }
27 }
28 </script>
Copy the code

To sum up, in the hook function of the server side pre-obtaining data, no additional operation should be carried out. Any additional operation on the data should be carried out under the vuEX system. Vuex should use the lazy registration scheme under the Vue SSR scheme.

3. The interface proxy is faulty

Because many front-end interfaces are developed offline, you need to switch the address of the interface agent. The most common ones we use are fiddler and Charles. However, SSR uses the server, not the browser, for data preacquisition, so it cannot be represented by either tool.

There are two methods. One is to change the host address of the server. This method only needs to change the host of the local machine in the development phase, but it needs to change the host of the server in the test phase. The second approach is to use the proxy function of AXIos, because AXIos is naturally adapted to SSR, so 99% of projects use it. And its own proxy function, can help us to facilitate the interface proxy.

The proxy configuration file is as follows:

 1 // config/dev-host
 2 export default {
 3   https: '192.168.183.80'.4   http: '192.168.183.80'
 5 }
 6The proxy setting code is as follows:7 import Axios from 'axios';
 8 import https from 'https';
 9 import devHost from '.. /config/dev-host';
10 
11 let proxy = (isDev) = > {
12  if(! isDev) {13    return;
14  }
15  let proxy = null;
16  if (devHost.https) {
17    // If an HTTPS proxy exists, set the HTTPS proxy
18    proxy = {
19      host: devHost.https,
20      port: 443
21    };
22    // You can configure certificate authentication to ignore HTTPS
23    Axios.interceptors.request.use(function (config) {
24      config.httpsAgent = new https.Agent({rejectUnauthorized: false});
25      return config;
26    });
27    Axios.defaults.proxy = proxy;
28  } else if (devHost.http) {
29    // If an HTTP proxy exists, set the HTTP proxy
30    proxy = {
31      host: devHost.http,
32      port: 80
33    };
34    Axios.defaults.proxy = proxy;
35  }
36 }
37 export default proxy
Copy the code
4. Cookies to penetrate

The HTTP request of the client first reaches the SSR server, and then the SSR server obtains the corresponding interface data from the back-end server. The client carries cookie data in its request to the SSR server. However, in the process of the SSR server requesting the back-end interface, there is no corresponding cookie data. Therefore, when the SSR server makes the interface request, we need to manually get the cookie from the client and send it to the back-end server. If axios is used here, you can manually set the HEADERS field of the AXIOS request to achieve cookie penetration.

 1 let addCookie = (config) = > {
 2    // Determine whether the client request carries cookies
 3    if(! process.browser && config.req && config.req.headers && config.req.headers.cookie){4        // Add the cookie carried by the client request to the SSR server request header
 5        config.headers =  config.headers || {};
 6        config.headers.cookie = config.req.headers.cookie;
 7        delete config.req;
 8    }
 9    return config;
10 }
Copy the code
5. Routing mode

Vue has two routing modes: hash mode (#/hasha/hashb) and History mode (/historya/historyb). The hash route cannot be submitted to the server, so the SSR route needs to be in history mode.

Exception handling issues

1. Where do exceptions come from?

(1) Exceptions in the process of data pre-acquisition on the server, such as various exceptions in the interface request, and errors and exceptions in the process of data operation after data acquisition.

(2) Exceptions occur in the process of rendering the page after the end of the life cycle of server data preacquisition, including various syntax errors of operation data, such as fetching attribute of undefined.

2. How to handle exceptions

(1) Official treatment methods

Throw 500 error pages, experience unfriendly, product not accepted.

(2) Current methods

A. If an exception occurs during data preacquisition on the server, render the page, do not throw 500 exception pages, type error logs, and monitor access. At the same time, add a logo to the page, let the front page to make another attempt to get the data page rendering.

B. The page rendering process is abnormal. Since the current rendering process is carried out by a plug-in provided by VUE, exceptions are not easy to catch, and the probability of problems occurring at the same time is not very large, so no special processing has been done.

The code is as follows:

Entry-server.js server part:

 1 Promise.all(matchedComponents.map(component= > {
 2    // The code is omitted. See the official document
 3 })).then(() = > {
 4    // The code is omitted. See the official document
 5 }).catch(err= > {
 6    // The official code here directly throws an exception, thus going to the 500 error page
 7    // We do the following processing, first print the error log, add the log to the monitoring alarm, monitoring the exception
 8    console.log('rendererror'.'entry-server',err);
 9    // Second, add the server prerender error identifier, the front end get the logo after re-render
10    context.serverError = true;
11    // Finally, return the server vue instance as normal and avoid throwing 500
12    resolve(app)
13 })
Copy the code

Add the following js code to the index.template-html page template section:

 1 // Server rendering error id
 2 window.__serverRenderError = {{serverError || false}};    
 3Entry-client.js Client part:4 / /... Ignore irrelevant code
 5 router.onReady((currentRoute) = > {
 6    / /... Ignore irrelevant code
 7    // If you get the error status of the server, execute the client rendering program
 8    if(window.__serverRenderError){
 9        feCompatibleRende(currentRoute);
10    }
11    app.$mount('#app');
12 })    
13 
14 // The front-end route is rerendered when node reports an error
15 function feCompatibleRende(route){
16    let matched = router.getMatchedComponents(route);
17    console.log('Front-end compatible rendering execution');
18    Promise.all(matched.map(c= > {
19        if (c.preFetch) {
20            return c.preFetch({
21                store,
22                route,
23                req: {
24                    headers: {
25                        cookie: document.cookie
26                    }
27                }
28            })
29        }
30    })).then(() = > {
31        console.log('ok');
32    }).catch((e) = >{
33        console.error(e);
34    })
35 }
Copy the code

Summary: In a word, for a better experience, do not appear 500.

performance

SSR can improve the first screen loading speed, reduce the white screen time, through the following Settings can improve performance, reduce server resources, speed up access speed.

(1) Page level cache cache the rendered page into memory, and set the maximum cache number and cache time. Benefits: Significantly faster page access Costs: increased server memory usage

六四运动

1 const LRU = require('lru-cache'); Const microCache = LRU({4 Max: 100,// Max: 100, 5 maxAge: 6}) 7 // HTTP request processing 8 server.get('*', (req, 10 const hit = microcache.get (req.url) 11 const hit = microcache.get (req.url) 11 if (hit) {13 return res.end(hit) 14 } 15 renderer.renderToString((err, HTML) => {16 res.end(HTML) 17 // Cache the page in the cache object 18 microcache.set (req.url, HTML) 19}) 20})Copy the code

2) Component-level caching applies: purely static components, children of loops in V-for

  1. In most cases, you should not and do not need to cache singleton instance groups

(3) Interface-level cache

六四运动

2. Cache the universal interface into memory to reduce the server interface request time. 4.  5 import axios from 'axios' 6 import qs from 'qs' 7 import md5 from 'md5' 8 9 const LRU = require('lru-cache'); 10 const microCache = LRU({11 Max: 100,// Max: 100, 12 maxAge: 13}) 14 15 export default {16 get(url, data) {17 Generate a unique key 18 const key = md5(URL + json.stringify (data)) 19 // Return cache if hit 20 if (microcache.has (key)) {21 return Promise. Resolve (microcache.get (key)) 22} 23 return axios.get(URL,{params:data}).then(res => {24 // If caching is needed, 25 if (data.cache) microcache.set (key, res) 26 return res 27}) 28} 29}Copy the code

security

Because node services are being served, there are also security considerations.

(1) the DDOS attacks

The most basic DDOS attack is to use reasonable service requests to occupy too many service resources, so that legitimate users cannot get the service response

To deal with:

1. Upgrade hardware devices

The higher the hardware performance is, the stronger the service concurrency capability is. In this way, the access of normal users is not affected even if a small number of DDOS attacks occur.

2. Perform only the most basic processing on the server

In the server side does not do too much complex data processing, can effectively improve the SSR performance.

3. Only key information about key parts is displayed in logs

Excessive log printing consumes server resources and affects server performance.

4.DDOS traffic cleaning

Traffic cleaning devices can be deployed to clear DDoS attack traffic on the network and ensure normal traffic.

5.DDOS software and hardware firewall

The software firewall solution is designed to deploy the software firewall on the protected server. The advantages are low cost, convenience, and flexibility, but the disadvantages are limited function and resource occupation.

The hardware firewall solution is to install the firewall hardware. The advantage is good effect, but the disadvantage is high cost.

(2) the SQL injection

Is through the SQL command inserted into a Web form to submit or input domain name or page requests a query string, achieve finally cheat server performs malicious SQL commands For example: the game PC details page code for game.zhuanzhuan.com/detail/1001…

And the attacker will url for game.zhuanzhuan.com/detail/sele…

Perform the following operations: 1. Verify parameters

Add validation code to the entry file on the server to execute the validation rules of the component

六四运动

Let isValid = true 3 Components. ForEach ((Component) => {4 if (! isValid) return 5 if (typeof Component.options.validate ! IsValid = = = 'function') return 6 Component. The options. The validate (app. The context) 7}) 8 / / verification through returns 404 9 if (! isValid) { 10 // Render a 404 error page 11 return render404Page() 12 }Copy the code

(3) Data leakage

When VUEX is used, data leakage is likely to occur if lazy loading is not used.

For any situation where you need to log in to obtain data, it is recommended to do so not on the server, but only on the client