Refer to the link

Koa2-cors allows you to specify a single domain name, multiple domain names, and all domain names across domains

When a resource requests a resource from a different domain, protocol, or port than the server on which the resource itself resides, the resource initiates a cross-domain.

CORSCross-domain resource sharing

Cross Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to allow Web applications running on one Origin (domain) to access specified resources from different source servers.

corsConfiguration [koa2]

Allows all domain names to be accessed across domains

const cors = require('koa2-cors');
app.use(cors()); 
Copy the code

Specify a single domain name across domains

app.use(
     cors({
         origin: function(ctx) { // Set requests from the specified domain to be allowed
            return 'http://localhost:8080'; // only requests for http://localhost:8080 are allowed
        },
         maxAge: 5.// Specifies the validity period of this precheck request, in seconds.
        credentials: true.// Whether cookies can be sent
         allowMethods: ['GET'.'POST'.'PUT'.'DELETE'.'OPTIONS'].// Sets the allowed HTTP request methods
        allowHeaders: ['Content-Type'.'Authorization'.'Accept'].// Set all header fields supported by the server
        exposeHeaders: ['WWW-Authenticate'.'Server-Authorization'] // Set to get additional custom fields}));Copy the code

Multiple domain names can be configured across domains

app.use(
     cors({
         origin: function(ctx) { // Set requests from the specified domain to be allowed
            const whiteList = ['http://weipxiu.com'.'http://localhost:8081']; // Cross-domain whitelist
            let url = ctx.header.referer.substr(0,ctx.header.referer.length - 1); 
             if(whiteList.includes(url)){
                 return url // Note that the domain name cannot end with a /, otherwise it will not succeed, so I killed/via substr earlier
            }
             return 'http://localhost::3000' // By default, local requests to port 3000 are allowed across domains
        },
         maxAge: 5.// Specifies the validity period of this precheck request, in seconds.
         credentials: true.// Whether cookies can be sent
         allowMethods: ['GET'.'POST'.'PUT'.'DELETE'.'OPTIONS'].// Sets the allowed HTTP request methods
        allowHeaders: ['Content-Type'.'Authorization'.'Accept'].// Set all header fields supported by the server
        exposeHeaders: ['WWW-Authenticate'.'Server-Authorization'] // Set to get additional custom fields}));Copy the code

Problems encountered with withCredentials in the project

Problem description

In the actual project development, we encounter such a problem: after the user logs in successfully, we set a cookie for the user, and when the user visits the web page again, the user information is directly obtained from the cookie. The problem I ran into in the project was that I could not get user information from cookies, and the value I got was undefined

Set after successful logincookie

router.post('/smslogin'.async(ctx,next) => {
    // 1. Obtain data
    const qqEmail = ctx.request.body.qqEmail;
    const pin = ctx.request.body.pin;
    console.log(sms)
    console.log(qqEmail,pin)
    // // 2. Check whether the verification code is correct
    if(pin ! = sms) { ctx.body={err_code: 0.message: 'Verification code is not correct! '};
        sms = ' '
        return;
    }
    // 3. Query data
    let sqlStr = `SELECT * FROM users WHERE qqEmail = '${qqEmail}'`;
    let res = await query(sqlStr)
    if(res[0]){
      ctx.cookies.set('userId', res[0].userId, {
            domain: 'localhost'.// Write the domain name of the cookie
            path: '/'.// Write the path to the cookie
            maxAge: 2 * 60 * 60 * 1000.// Cookie validity period
            expires: new Date('2018-02-08'), // Cookie expiration time
            httpOnly: false.// Whether to obtain only in HTTP requests
            overwrite: false // Whether overwriting is allowed})}else{
      ctx.body={err_code:200.message:'Please register and log in! '}}});Copy the code

To obtaincookieThe data in the

router.get('/userinfo'.async(ctx,next) => {
    // 1.0 Gets parameters
    
    let userId = ctx.cookies.get('userId')  // Failed to get parameters here
    
    let res = await query(`SELECT * FROM users WHERE id = '${userId}'`)
    delete res[0].password
    ctx.body={
      success_code:200.message:res[0]}});Copy the code

Problem analysis

In the case of co-domain, the cookie in the current domain will be carried by default when we send the request, but in the case of cross-domain, the cookie in the request domain will not be carried by default. For example, http://domain-a.com site sends a request for http://api.domain-b.com/get. By default, cookies in the APi.domain-b.com domain are not carried.

In the project, the situation is that the localhost:8080 site receives and sends the localhost:3000 request, and the two ports are different, which constitutes cross-domain. Cross-domain does not carry cookies in the localhost:3000 domain by default.

Problem solving

To solve this problem, we need to make the cross-domain request carry a cookie, which is very simple:

The front-end processing

On the front end I use AXIos to make network requests

axios.defaults.withCredentials = true
Copy the code

The back-end processing

On the back end, we also need to set whether to allow the browser to carry cookie access, which means we need to set the credentials in the response header to true

credentials: true.// Whether cookies can be sent
Copy the code

In addition, we need to configure the CORS. We cannot allow cross-domain access for all domains:

That is, we cannot configure cORS this way.

const cors = require('koa2-cors');
app.use(cors()); 
Copy the code

The preferred course of action is

Multiple domain names can be configured across domains

app.use(
     cors({
         origin: function(ctx) { // Set requests from the specified domain to be allowed
            const whiteList = ['http://weipxiu.com'.'http://localhost:8081']; // Cross-domain whitelist
            let url = ctx.header.referer.substr(0,ctx.header.referer.length - 1); 
             if(whiteList.includes(url)){
                 return url // Note that the domain name cannot end with a /, otherwise it will not succeed, so I killed/via substr earlier
            }
             return 'http://localhost::3000' // By default, local requests to port 3000 are allowed across domains
        },
         maxAge: 5.// Specifies the validity period of this precheck request, in seconds.
         credentials: true.// Whether cookies can be sent
         allowMethods: ['GET'.'POST'.'PUT'.'DELETE'.'OPTIONS'].// Sets the allowed HTTP request methods
        allowHeaders: ['Content-Type'.'Authorization'.'Accept'].// Set all header fields supported by the server
        exposeHeaders: ['WWW-Authenticate'.'Server-Authorization'] // Set to get additional custom fields}));Copy the code

At this point, the problem is solved.

While the problem has been solved, we should also consider why cORS could not be set to allow all domain names to cross domains in the above case.

For security reasons, setting cORS to Allow all domain names to cross domains allows us to obtain the value of the cookie in the back end. There is no problem in the back end, but the server will block the response of Access-Control-Allow-Origin: * for security reasons.