In many projects, permissions verification interfaces are involved. If there is an interface request from a third party, we will ask the back end to do a forwarding for us. However, for some simple purely front-end projects, we can build a simple Node.js service to forward interface requests.

background

The background is a bit long, which describes the scene and the process of thinking. If you are not interested, you can skip to the next part.

Recently I have been working on a 3D model presentation library, and this third party model library needs to be initialized using authorized tokens.

The model library provides two ways to obtain tokens:

1. The token is generated directly through the configuration background of the model library. However, if the token is not used for 12 consecutive hours, the previous token will expire and you need to obtain it from the configuration background again.

2. Access tokens can be obtained in real time according to the appKey and appSecret of the application through the server interface provided by the model library.

If we use the first method, we must ensure that every 12 hours, we need to use the current token to access the page, this scheme is not elegant at all, direct pass.

The second option is to get it by accessing the API, and the first thing THAT comes to my mind is whether it’s possible to get it asynchronously on the front end.

First of all, this project is just a small demo, don’t worry about the leak of AppKey, Secret. So I thought it would be possible to access the corresponding interface directly from the page, so here is the implementation :(the project is initialized based on umijs)

import { request } from 'umi'; const Authorization = btoa('appKey:appSecret'); export async function getOauthToken():Promise<string> { return new Promise((resolve) => { request('/oauth2/token', { prefix: 'https://api.xxx.com', method: 'POST', headers: { Authorization: `Basic ${Authorization}`, }, }).then((res) => { if (res.code === 'success') { resolve(res.data.token); }}); }); }Copy the code

In fact, it is to request an interface to obtain the token. Error (CORS) :

CORS: Cross-Origin Resource Sharing.

Cross-source resource sharing (CORS) (or colloquically translated as cross-domain resource sharing) is an HTTP headers based mechanism that allows the server to identify other Origin (domains, protocols, and ports) in addition to its own, so that browsers can access and load these resources. Cross-source resource sharing also uses a mechanism to check whether the server will allow the real request to be sent by issuing a “precheck” request to the server-hosted cross-source resource through the browser. In precheck, the header sent by the browser identifies the HTTP method and the header that will be used in the real request.

For security reasons, browsers restrict cross-source HTTP requests made within scripts. For example, the XMLHttpRequest and Fetch apis follow the same origin policy. This means that Web applications using these apis can only request HTTP resources from the same domain where the application was loaded, unless the response packet contains the correct CORS response header.

CORS is a common problem when the front and back ends are separated. The general solution is to set the return header on the server: access-control-allow-Origin, access-control-allow-Methods, access-control-allow-headers and so on.

However, this server-side setup is not suitable for the above scenario because we are using a third-party service and cannot set the return header. In this case, an intermediate service is used for forwarding, because requests from the server side are not restricted by the same origin policy.

UmiJS SSR

Since the project was initialized based on UMiJS, I originally wanted to use server-side rendering directly (UMijs SSR). Umi provides a method called getInitialProps for page level data retrieval.

Specific modifications are as follows:

{SSR: {}} // Add getInitialProps import fetch from 'umi-request'; import { isBrowser } from 'umi'; function IndexPage(props) { const { data } = props; return ( <div> testToken: {JSON.stringify(data)} </div> ); } IndexPage.getInitialProps = async () => { if (isBrowser) { const Authorization = btoa('appKey:appSecret'); const res = await fetch.post('https://api.xxx.com/oauth2/token', { headers: { Authorization, } }) return { data: res } } return { data: '' } } export default IndexPage;Copy the code

For more information on UmiJS SSR, see the official demo: github.com/umijs/umi-e… .

This is probably the easiest way to modify the configuration file and add the interface request to the supplied getInitialProps interface. And we don’t have to worry about the appKey and appSecret being exposed, but if we look at the HTML that’s returned from the page, there’s no Authorization variable declared in the getInitialProps method.

Node.js service based on Koa2

The UmiJS SSR scheme above, which limits scaffolding and framing, has certain technical limitations. A more common solution is to build your own Node.js service. Here’s how to build a node.js service for forwarding based on Koa2.

Let’s start with Koa2:

Koa is a new Web framework built by the same people behind Express that aims to be a smaller, more expressive, and more robust building block for web application and API development. By using async functions, Koa helps you discard callbacks and greatly enhances error handling. Koa doesn’t bundle any middleware, but rather provides an elegant way to write server-side applications quickly and happily.

Initialize the project

First follow these steps to initialize the Koa2 project

  • Install the Node.js environment
  • npm initInitialize the project
  • Installing KOA and other dependencies:npm install koa koa-router
  • Create entry files in the project root directoryindex.js
const Koa = require('koa'); // introduce koa-router const router = require('koa-router'); const app = new Koa(); /* const router = new router (); / * * / router in the formulation of the routing rules get ('/', (CTX) = > {CTX. Body = 'Hello World'; }) app /* Apply routing rules to the Koa application instance */.use(router-.routes ()).use(router-.allowedMethods ()) app.listen(8081, () => { console.log('listening on port 8081 ... '); });Copy the code
  • Run entry file:node index.js
  • Browser accesshttp://localhost:8081/You can see that the page displays the familiar Hello World

The agent requests

To complete the rest of the forward work, first install axios (NPM install axois), then do the interface request and forward:

./index.js

const Koa = require('koa'); const Router = require('koa-router'); const requestToken = require('./requestToken'); const app = new Koa(); /* const router = new router (); Get ('/ API /token', async (CTX) => {const result = await requestToken() cx.body = result; }) app /* Apply routing rules to the Koa application instance */.use(router-.routes ()).use(router-.allowedMethods ()) app.listen(8081, () => { console.log('listening on port 8081 ... '); });Copy the code

./requestToken.js

const axios = require("axios"); // Base64 const Authorization = new Buffer('appKey:appSecret').toString(' Base64 '); module.exports = async () => { return new Promise((resolve) => { axios.post( "https://api.xxx.com/oauth2/token", {}, { headers: { Authorization: `Basic ${Authorization}`, }, } ).then((res) => { if (res.data.code === "success") { resolve(res.data.data.token); }}); }); };Copy the code

Execution node index, js, visit http://localhost:8081/api/token, you can see the back of the token.

If the development is local, the front-end page of the dev-server port is different, access will also encounter CORS error. We can directly set the return header of the/API /token interface in./index.js:

router.get('/api/token', Async (CTX) => {const result = await requestToken() // Allow await requestToken from all domain names ctx.set(" access-control-allow-origin ", "*"); Ctx. set(" access-control-allow-methods ", "OPTIONS, GET"); // The fields are required. It's also a comma-separated string, Ctx. set(" requested-with, accept, Origin, content-type"); const result = await requestToken() ctx.body = result; })Copy the code

The deployment of

Next, a brief description of how to deploy on the server side.

The first step is to pull the code on the server side and install the dependencies (including the Node.js environment).

It is not recommended to use the node index.js command to start the service, because we need to run the service in the background. Otherwise, the node service will be stopped directly after we disconnect the connection.

We can run nohup node index.js and let the service run in the background.

It is more recommended to use Forerver or pM2 to manage the Node.js service process.

Take PM2 as an example:

$NPM install pm2 -g # $pm2 start index. Js # $pm2 ls # $pm2Copy the code

This completes starting the Node.js service on the server, and the important step is to configure forwarding.

Here is my new Nginx configuration:

location = /api/token {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
proxy_pass http://localhost:8081;
}
Copy the code

If you already have access-control-allow-origin headers in the service, you can remove the add_header configuration.

Wechat subscription number

Welcome to pay attention to the wechat subscription number [front end test Baodian.com], we will frequently update the front end test related interview topic articles, as well as the front end related technical articles to share.

Micro channel small program

At the same time, we also welcome you to visit our wechat mini program, which aims to provide interview questions collection and arrangement for the front end interviewers, and provide free online mock interview service.

Welcome to scan the code to pay attention to our small program [front end test treasure], I hope in your interview process, can help you.