Why introduce the Node middle tier?
In fact, any technology is closely related to its application scenario. Here we repeatedly talk about SSR, in fact, we do not have to do it, SSR to solve the biggest pain point is SEO, but it has brought more expensive costs. Not only because of the service side rendering needs to be more complex processing logic, but also because of homogeneous process need the server and the client code is executed again, although it to the client and no matter, but for the service side is great pressure, because of the large number of visitors, for each visit will be in addition to execute on the server and compile the code again to compute, It takes a lot of performance out of the server side and increases the cost. If the traffic is large enough, the pressure that a single server could bear when SSR was not used may increase to 10 now. The pain point is SEO, but if the actual SEO requirements are not high, then the use of SSR is unnecessary.
So again, why introduce Node as a middle tier? Where is it in the middle? And what scenarios are solved?
In development mode without the front and back end separation of the middle tier, the front end typically requests the back end interface directly. However, in real scenarios, the data format provided by the back-end is not what the front-end wants, but the interface format cannot be changed for performance reasons or other reasons. In this case, some additional data processing operations need to be performed in the front-end. There is nothing wrong with the front-end handling of data, but when the amount of data becomes huge, it will cause huge performance loss on the client side, and even affect the user experience. At this point, the concept of node middle tier comes into being.
It finally solves the problem of front – and back-end collaboration.
The general workflow of the middle layer is like this: each time the front-end sends a request, it requests the interface of the Node layer, and then the node forwards the corresponding front-end request. After obtaining the data, the Node layer performs the corresponding data calculation and other processing operations, and then returns it to the front end. This lets the Node layer take over the data for the front end.
Second, the introduction of middle layer in SSR framework
In the SSR framework built before, the server and client requests use the same set of request back-end interface code, but this is not scientific.
For clients, it’s best to go through the Node middle tier. For this SSR project, the server node starts is a middle tier role, so the server can directly request the real back-end interface to perform the data request.
//actions.js
// The server parameter indicates whether the current request is on the Node server
const getUrl = (server) = > {
return server ? 'XXXX (back-end interface address)' : '/ API/sanyuan. Json (node interface)';
}
// The server parameter is passed from the Home component,
// Call this action in componentDidMount with false,
// Pass true when called in loadData, so there is no component code attached here
export const getHomeList = (server) = > {
return dispatch= > {
return axios.get(getUrl(server))
.then((res) = > {
const list = res.data.data;
dispatch(changeList(list))
})
}
}
Copy the code
Server /index.js should forward the request to the front end, which is directly used as a proxy, or node can send an HTTP request to the back end alone.
// Add the following code
import proxy from 'express-http-proxy';
// It intercepts the/API part of the front-end request address and changes it to another address
app.use('/api', proxy('http://xxxxxx(server address)', {
proxyReqPathResolver: function(req) {
return '/api'+req.url; }}));Copy the code
Third, request code optimization
There is room for optimization in the requested code, as the server parameters above are not actually passed.
Now we use axios instance and Thunk withExtraArgument to do some wrapping.
/ / the new server/request. Js
import axios from 'axios'
const instance = axios.create({
baseURL: 'http://xxxxxx(server address)'
})
export default instance
/ / the new client/request. Js
import axios from 'axios'
const instance = axios.create({
// Is the node service of the current path
baseURL: '/'
})
export default instance
Copy the code
Then make a tweak to the global store code:
import {createStore, applyMiddleware, combineReducers} from 'redux';
import thunk from 'redux-thunk';
import { reducer as homeReducer } from '.. /containers/Home/store';
import clientAxios from '.. /client/request';
import serverAxios from '.. /server/request';
const reducer = combineReducers({
home: homeReducer
})
export const getStore = (a)= > {
// Use thunk middleware with serverAxios
return createStore(reducer, applyMiddleware(thunk.withExtraArgument(serverAxios)));
}
export const getClientStore = (a)= > {
const defaultState = window.context ? window.context.state : {};
// Use thunk middleware with clientAxios
return createStore(reducer, defaultState, applyMiddleware(thunk.withExtraArgument(clientAxios)));
}
Copy the code
Now the action requesting data in the Home component does not need to be passed. The request code in actions.js is as follows:
export const getHomeList = (a)= > {
// The default third argument in the return function is the axios instance passed in by withExtraArgument
return (dispatch, getState, axiosInstance) = > {
return axiosInstance.get('/api/sanyuan.json')
.then((res) = > {
const list = res.data.data;
console.log(res)
dispatch(changeList(list))
})
}
}
Copy the code
At this point, code optimization is done, and this kind of code encapsulation technique can be applied to other projects, which is actually quite elegant.