koa2怎么处理OPTIONS请求

自己练习用koa2去写接口的时候,遇到了ajax请求GET接口,例如如下

$.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')
    }
})

然后会发生一次OPTIONS的请求,但是一直接受不到,koa2的代码如下

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,
};

可是浏览器却一直显示的是404 找不到,也没有走'OPTIONS /user_new': fn_usrs_option, 也没有走这个'GET /user_new': fn_usrs_new,

koa2代码的index.js如下

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...');
});

controller 文件的内容如下

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和handler通过。不知道为什么?找了很多原因也没有找到

阅读 1k
评论
    3 个回答

    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,
    };
    这个是路由的地址,接口的地址,我本地的服务,

    解决的方法就是在集中处理错误的地方统一设置
    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");
    这些东西,可以挑着用,看项目的需要。其次还有就是OPTIONS确实是router内容自己处理,我们不需要处理,只需要告诉OPTIONS请求返回200就行,上面的函数也就变成了下面这个样子

    // 集中处理错误
    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
        };
      }
    };
    评论 赞赏