V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
deepred
V2EX  ›  Node.js

koa2 给某条特定的 url 设置 cors 后,前端 ajax 自定义头部后就无法跨域,去掉头部就能跨域

  •  
  •   deepred · 2018-06-11 23:08:19 +08:00 · 5877 次点击
    这是一个创建于 2361 天前的主题,其中的信息可能已经有所发展或是发生改变。

    app.js

    const Koa = require('koa');
    const Router = require('koa-router');
    const router = new Router();
    const app = new Koa();
    
    
    
    router.all('*',function (ctx, next) {
        ctx.set('Access-Control-Allow-Origin', '*');
        ctx.set('Access-Control-Allow-Headers', 'Content-Type, myheader');
        ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
    
        next();
      });
    
    
    router.post('/api/test/', (ctx, next) => {
        ctx.body = {
            status: 'success'
        }
    });
    
    router.post('/api/test2/', (ctx, next) => {
        ctx.body = {
            status: 'success'
        }
    });
    
    
    
    app.use(router.routes()).use(router.allowedMethods());
    
    
    
    app.listen(8089);
    
    
    console.log('server start at 8089')
    

    前端自定义头部myheader

    axios.post(`http://localhost:8089/api/test`, null, { headers: { 'myheader': 'test' }})
            .then(response => {
                console.log(response.data);
            });
    

    后台把所有的接口都设置成 cors,前端是可以自定义头部的。

    但是如果我只是让其中一个接口 cors

    const Koa = require('koa');
    const Router = require('koa-router');
    const router = new Router();
    const app = new Koa();
    
    
    
    router.post('/api/test/', (ctx, next) => {
        ctx.set('Access-Control-Allow-Origin', '*');
        ctx.set('Access-Control-Allow-Headers', 'Content-Type, myheader');
        ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
        ctx.body = {
            status: 'success'
        }
    });
    
    router.post('/api/test2/', (ctx, next) => {
        ctx.body = {
            status: 'success'
        }
    });
    
    
    
    app.use(router.routes()).use(router.allowedMethods());
    
    
    
    app.listen(8089);
    
    
    console.log('server start at 8089')
    

    这时前端设置自定义头部,就会报错 说没有No 'Access-Control-Allow-Origin' header,但是我已经设置过Access-Control-Allow-Headers了。

    如果前端把自定义头部去掉,这时又能跨域成功

    // 正常跨域
    axios.post(`http://localhost:8089/api/test`)
            .then(response => {
                console.log(response.data);
            });
    

    求解决方法

    7 条回复    2018-06-20 09:35:05 +08:00
    Sparetire
        1
    Sparetire  
       2018-06-12 01:39:00 +08:00 via Android
    因为你这里单独接口的时候没有对 option 请求做出响应
    deepred
        2
    deepred  
    OP
       2018-06-12 08:07:04 +08:00
    @Sparetire 嗯,就是这个原因
    deepred
        3
    deepred  
    OP
       2018-06-12 08:12:36 +08:00
    @Sparetire 但是为啥单独接口的时候,我不加自定义头部,虽然没对 option 做响应,但是也跨域成功了?
    KuroNekoFan
        4
    KuroNekoFan  
       2018-06-12 09:12:36 +08:00 via iPhone
    我没看错的话你代码不是就是这个意思吗……上面的代码是 router.all ,下面是 post (“ api/test ”)
    dtysky
        5
    dtysky  
       2018-06-12 10:03:25 +08:00 via Android
    详细看看跨域控制协议吧,只有 simple request 不会发预置 options 请求,而它是有限制的(比如只能报告某些头部)。
    Sparetire
        6
    Sparetire  
       2018-06-12 10:40:16 +08:00 via Android
    @deepred 因为这里不带自定义头部不需要 option 请求,具体参考同源策略和跨域协商的细节
    wotemelon
        7
    wotemelon  
       2018-06-20 09:35:05 +08:00
    router.post('/api/test/', (ctx, next) => {
    ctx.set('Access-Control-Allow-Origin', '*');
    ctx.set('Access-Control-Allow-Headers', 'Content-Type, myheader');
    ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
    ctx.body = {
    status: 'success'
    }
    });

    你这里处理了`post`请求啊,你要把`post`改成`all`。在你没有单独拦截接口的时候,你用的是`all`,当然包括了`option`
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3531 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 04:40 · PVG 12:40 · LAX 20:40 · JFK 23:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.