How does koa2 handle OPTIONS requests

when I was practicing writing an interface with koa2, I encountered an ajax request for GET interface, such as the following

$.ajax({
    type: "GET",
    url:"http://localhost:3000/user_new",
    headers: {
      "Accept": "application/json",
      "Content-Type": "application/json;charset=utf-8",
      "Authorization": "JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTJjYjA5MjFjMjM0NDgzODhjMDQ1Mzg2N2QzZDI0NzUiLCJjb21wYW55X2lkIjoiNzM2ZDc5YjQ1NTkzNDU2NWE4ODljYjJmOTBhOTNlNzIiLCJzdGFmZl9pZCI6IjhlODM2MjFmZjQ3YTRhZGY4NjU4NGNhNWYxNDRmYzc0IiwidGVuYW50X2lkIjoiMTliMDQyMGM3ODViNGNlN2IxODNmMTFjMjY0M2I4YmUifQ.D7Mrba-lB94iSWr2pHAtS4KUkC_g06lJVHutj0MIu1Q"
    },
    success: function (data, textStatus) {
      console.log("123123")

    },
    error: function (a,b,c) {
      console.log("2222222")
    }
})

then a request from OPTIONS occurs, but it can"t be accepted all the time. The code for koa2 is as follows

const fn_usrs = async (ctx, next) => {
  let cb = ctx.request.query.callback;
  if (cb) { //ajax jsonp
    ctx.response.body = cb + "(" + JSON.stringify(jsonData) + ")";
  }else{ //
    // ctx.set("Access-Control-Allow-Origin", "*") //ajax json
    ctx.response.body = "{}"; //proxy 
  }
  
}
const fn_usrs_option = async(ctx, next) => {
  // ctx.set("Access-Control-Allow-Origin", "*");
  if (ctx.request.method == "OPTIONS") {
    ctx.response.status = 200
  }
  ctx.response.status = 200
}

module.exports = {
  "GET /user_new": fn_usrs_new,
  "OPTIONS /user_new": fn_usrs_option,
};

but the browser always shows that 404 can"t be found, and it doesn"t go to "OPTIONS / user_new": fn_usrs_option, nor to this " GET / user_new": fn_usrs_new,

.

the index.js of the koa2 code is as follows

const Koa = require("koa");
const app = new Koa();
const path = require("path");
const static = require("koa-static");
const bodyParser = require("koa-bodyparser");
const router = require("koa-router")();
const controller = require("./server/index.js");


// 
const staticPath = "./static";
app.use(static(
  path.join( __dirname,  staticPath)
))

// ejs 
const views = require("koa-views")
app.use(views(path.join(__dirname, "./view"), {
  extension: "ejs"
}))
// 
const handler = async (ctx, next) => {
  // log request URL:
  // ctx.set("Access-Control-Allow-Origin", "*");
  // ctx.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
  console.log(`Process ${ctx.request.method} ${ctx.request.url}`);
  try {
    await next();
    console.log("handler")
  } catch (err) {
    console.log("handler")
    ctx.response.status = err.statusCode || err.status || 500;
    ctx.response.body = {
      message: err.message
    };
  }
};
// catch. onerror ctx.app.emit("error", err, ctx);
// app.on("error", function(err) {
//   console.log("logging error ", err.message);
// });
app.use(handler)


app.use(bodyParser()); // post
app.use(controller()) //  ----

app.listen(3000, () => {
  console.log("app started at port 3000...");
});

the contents of the controller file are as follows

const fs = require("fs");

function addMapping(router, mapping) {
  for (var url in mapping) {
    if (url.startsWith("GET ")) {
      var path = url.substring(4);
      router.get(path, mapping[url]);
      // console.log(`register URL mapping: GET ${path}`);
    } else if (url.startsWith("OPTIONS ")) {
      var path = url.substring(8);
      router.get(path, mapping[url]);

    } else if (url.startsWith("POST ")) {
      var path = url.substring(5);
      router.post(path, mapping[url]);
      // console.log(`register URL mapping: POST ${path}`);
    } else if (url.startsWith("PUT ")) {
      var path = url.substring(4);
      router.put(path, mapping[url]);
      // console.log(`register URL mapping: PUT ${path}`);
    } else if (url.startsWith("DELETE ")) {
      var path = url.substring(7);
      router.del(path, mapping[url]);
      // console.log(`register URL mapping: DELETE ${path}`);
    } else {
      console.log(`invalid URL: ${url}`);
    }
  }
}

function addControllers(router, dir) {
  const files = fs.readdirSync(__dirname + "/" + dir).filter((f) => {
    return f !== "index.js";
  })
  files.forEach((f) => {
    // console.log(`process controller: ${f}...`);
    let mapping = require(__dirname + "/" + f);
    addMapping(router, mapping);
  });
}

module.exports = function(dir) {
  let controllers_dir = dir || "/",
    router = require("koa-router")();
  addControllers(router, controllers_dir);
  return router.routes();
};
Process and handler are printed directly when

is called. I don"t know why? I looked for a lot of reasons, but I couldn"t find

.
Apr.02,2021

module.exports = {
'GET / user_new': fn_usrs_new,
' OPTIONS / user_new': fn_usrs_option,
'GET / users': fn_usrs,
' POST / users': add_usrs,
'DELETE / users/:id': del_usrs,
};
this is the address of the route, the address of the interface, my local service,

the solution is to uniformly set
ctx.set ("Access-Control-Allow-Origin", "*"),
ctx.set ("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"),
ctx.set ("Access-Control-Max-Age", "3600"),
ctx.set ("Access-Control-Allow-Headers", "Xmuri requestedhouse with theory AuthorizationContentType reception accept") where errors are handled centrally.
ctx.set ("Access-Control-Allow-Credentials", "true");
these things can be picked and used, depending on the needs of the project. Secondly, OPTIONS does handle the router content on its own. We don't need to deal with it. We just need to tell OPTIONS that the request returns 200, and the above function will look like this

.
// 
const handler = async (ctx, next) => {
  // log request URL:
  ctx.set("Access-Control-Allow-Origin", "*");
  ctx.set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
  ctx.set("Access-Control-Max-Age", "3600");
  ctx.set("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type,Accept");
  ctx.set("Access-Control-Allow-Credentials", "true");
  if (ctx.request.method == "OPTIONS") {
    ctx.response.status = 200
  }
  console.log(`Process ${ctx.request.method} ${ctx.request.url}`);
  try {
    await next();
    console.log('handler')
  } catch (err) {
    console.log('handler')
    ctx.response.status = err.statusCode || err.status || 500;
    ctx.response.body = {
      message: err.message
    };
  }
};

first of all, if you add Authorization to your header, it is not a simple request;
the best way is that the interface and the page are in the same domain.


the OPtion request is a pre-request. Why do you accept the pre-request? False propositions, right?

MySQL Query : SELECT * FROM `codeshelper`.`v9_news` WHERE status=99 AND catid='6' ORDER BY rand() LIMIT 5
MySQL Error : Disk full (/tmp/#sql-temptable-64f5-1e46953-4cf64.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
MySQL Errno : 1021
Message : Disk full (/tmp/#sql-temptable-64f5-1e46953-4cf64.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
Need Help?