V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
xiaochong0302
V2EX  ›  NGINX

NGINX 配置跨域支持的正确方式

  •  
  •   xiaochong0302 · 2020-10-20 11:44:18 +08:00 · 5570 次点击
    这是一个创建于 1499 天前的主题,其中的信息可能已经有所发展或是发生改变。

    NGINX 配置跨域 CORS 支持

    这两天在搞 酷瓜云网课 的 app,采用 uni-app 做全端支持,现学现卖,目前算是入门了。

    在做 H5 的时候难免会跨域请求后端 API,虽然用 HBuilder 内置的浏览器不会有跨域问题(这个应该是做了内部处理),但是那个内置浏览器真尼妈坑爹,过一会就会卡死,导致 HBuilder 无响应,杀进程也是无济于事,只能重启,重复几次谁受的了。后来发现用外部的浏览器不会有这个问题,但是又面临跨域。

    这里采用配置 nginx 来支持 CORS,这样的话就不用动任何代码了。正确的配置如下:

    location ~ \.php$ {
    
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE' always;
            add_header 'Access-Control-Allow-Headers' '*' always;
            add_header 'Access-Control-Max-Age' 1728000 always;
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            return 204;
        }
    
        if ($request_method ~* '(GET|POST|DELETE|PUT)') {
            add_header 'Access-Control-Allow-Origin' '*' always;
        }
    
    }
    

    PS:网上很多都是采集,粘贴复制的垃圾文章,完全没有去验证的,碰到了会浪费还多时间,还会把你带坑里去。

    第 1 条附言  ·  2020-10-20 19:31:59 +08:00

    已经在后端代码里做控制了,各位别再 DUI 我了,手动哭脸!!!

    public function setCors()
    {
        /**
        * @var Config $config
        */
        $config = Di::getDefault()->getShared('config');
    
        $enabled = $config->path('cors.enabled');
    
        if (!$enabled) return;
    
        $allowOrigin = $config->path('cors.allow_origin');
        $allowHeaders = $config->path('cors.allow_headers');
        $allowMethods = $config->path('cors.allow_methods');
    
        /**
        * @var HttpResponse $response
        */
        $response = Di::getDefault()->getShared('response');
    
        /**
        * @var HttpRequest $request
        */
        $request = Di::getDefault()->getShared('request');
    
        $response->setHeader('Access-Control-Allow-Origin', $allowOrigin);
    
        if ($request->isOptions()) {
            $response->setHeader('Access-Control-Allow-Headers', $allowHeaders);
            $response->setHeader('Access-Control-Allow-Methods', $allowMethods);
        }
    }
    
    21 条回复    2020-10-21 10:01:51 +08:00
    eudore
        1
    eudore  
       2020-10-20 11:53:10 +08:00
    顶一个,逻辑正确。

    在跨越时,options 请求需要返回全部相关 header 和 204,非 option 必须返回 Access-Control-Allow-Origin 然后继续处理;origin 是请求必要的 header 。

    [https://github.com/eudore/eudore/blob/master/middleware/cors.go]( https://github.com/eudore/eudore/blob/master/middleware/cors.go)
    KuroNekoFan
        2
    KuroNekoFan  
       2020-10-20 11:57:19 +08:00
    cors 跨域挺烦人的,如果非必要,直接把页面和后端置同域是个更好的选择
    个人认为 cors 跨域的场景应该是一些提供一些第三方公共资源
    xiaochong0302
        3
    xiaochong0302  
    OP
       2020-10-20 12:38:08 +08:00
    @eudore 是的,很多人都是一股脑的全部返回
    @KuroNekoFan 我的开发环境是 linux, 弄 app 用到了 uni-app,它的开发工具 hbuilder 又没有 linux 版本的,没办法在虚拟机里面搭了个 windows 环境
    renmu123
        4
    renmu123  
       2020-10-20 13:22:16 +08:00 via Android
    嫌麻烦其实可以直接找个跨域的中间件,配置什么也比较多,基本也不会出什么 bug
    356693212
        5
    356693212  
       2020-10-20 14:39:17 +08:00
    你这理论上也不对,*不能满足 cookie 携带的问题,勉强够用吧,等遇到问题再说吧
    raysonlu
        6
    raysonlu  
       2020-10-20 15:05:46 +08:00
    对比这种*号方案,在实际生产环境上,我觉得有仅仅支持二级域名跨域的方案,会有意义些。
    est
        7
    est  
       2020-10-20 15:08:47 +08:00
    Access-Control-Allow-Origin: 不能加账号密码。。。得指定具体 origin 。。。


    For requests without credentials, the literal value "*" can be specified, as a wildcard; the value tells browsers to allow requesting code from any origin to access the resource. Attempting to use the wildcard with credentials will result in an error.


    https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin


    所以可以通过 $http_origin 来代替 *
    est
        8
    est  
       2020-10-20 15:09:35 +08:00
    然后 add_header 还有个问题就是 rewrite 比如 http 升级 https 的不会带上,也会导致跨域失败。
    rrfeng
        9
    rrfeng  
       2020-10-20 15:21:53 +08:00   ❤️ 1
    你这相当于废掉了 CORS 。
    人家给你造了一把锁锁你家门,你直接把门拆了说我不要……还『正确方式』呢。
    xiaochong0302
        10
    xiaochong0302  
    OP
       2020-10-20 16:13:21 +08:00
    @356693212
    @raysonlu
    @est
    @rrfeng
    走的 API 请求,所以不用 COOKIE,上面只是示例,具体的要按自己的需求来调整

    自然是在后端代码里面支持更可控,nginx 也只是一个方案而已
    zpfhbyx
        11
    zpfhbyx  
       2020-10-20 16:16:48 +08:00
    更倾向于中间件.后端接口来控制..你这每次加个 origin 都要 reload 一次服务器..单机问题不大..集群的话会疯..
    PonysDad
        12
    PonysDad  
       2020-10-20 17:50:50 +08:00
    这样配置,那 CORS 还有啥子意义,来者不拒啊.
    bigNewsMaker
        13
    bigNewsMaker  
       2020-10-20 18:13:02 +08:00
    梭哈编程,能跑就行
    xiaochong0302
        14
    xiaochong0302  
    OP
       2020-10-20 19:29:08 +08:00
    已经在后端代码里做控制了,各位别再 DUI 我了,手动哭脸!!!

    ```
    public function setCors()
    {
    /**
    * @var Config $config
    */
    $config = Di::getDefault()->getShared('config');

    $enabled = $config->path('cors.enabled');

    if (!$enabled) return;

    $allowOrigin = $config->path('cors.allow_origin');
    $allowHeaders = $config->path('cors.allow_headers');
    $allowMethods = $config->path('cors.allow_methods');

    /**
    * @var HttpResponse $response
    */
    $response = Di::getDefault()->getShared('response');

    /**
    * @var HttpRequest $request
    */
    $request = Di::getDefault()->getShared('request');

    $response->setHeader('Access-Control-Allow-Origin', $allowOrigin);

    if ($request->isOptions()) {
    $response->setHeader('Access-Control-Allow-Headers', $allowHeaders);
    $response->setHeader('Access-Control-Allow-Methods', $allowMethods);
    }
    }
    ```
    tingyunsay
        15
    tingyunsay  
       2020-10-20 19:47:03 +08:00
    我是截取 Referer 和 Origin 两个来判断是否跨域,基本上 pc 端全兼容..
    ivanshaoaz
        16
    ivanshaoaz  
       2020-10-20 20:34:44 +08:00
    @xiaochong0302 #14 phalcon 啊
    xiaochong0302
        17
    xiaochong0302  
    OP
       2020-10-20 20:44:10 +08:00
    @ivanshaoaz 大佬,这都能看出来呀
    just1
        18
    just1  
       2020-10-20 20:54:57 +08:00
    如果你是问问题,那么你在代码里写了不告诉大家这没问题,反正解决了就好。
    你放个半吊子在这告诉大家是正确方式,还不说明,不 dui 你 dui 谁
    ivanshaoaz
        19
    ivanshaoaz  
       2020-10-20 21:02:58 +08:00
    @xiaochong0302 #17 我可不是大佬,最近在用 phalcon4 写项目
    fumichael
        20
    fumichael  
       2020-10-21 09:24:35 +08:00
    @est #8 我昨天用楼主的方案想代理 smms 的上传接口,结果失败了,还没弄清楚原因
    zpfhbyx
        21
    zpfhbyx  
       2020-10-21 10:01:51 +08:00
    在 dui 一下.. 你这 origin 多个时候不生效啊. 应该是配置那是数组判断是不是在数组,
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2791 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:18 · PVG 23:18 · LAX 07:18 · JFK 10:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.