NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
xiaochong0302
V2EX  ›  NGINX

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

  •  
  •   xiaochong0302 · Oct 20, 2020 · 6269 views
    This topic created in 2029 days ago, the information mentioned may be changed or developed.

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

    Supplement 1  ·  Oct 20, 2020

    已经在后端代码里做控制了,各位别再 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 replies    2020-10-21 10:01:51 +08:00
    eudore
        1
    eudore  
       Oct 20, 2020
    顶一个,逻辑正确。

    在跨越时,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  
       Oct 20, 2020
    cors 跨域挺烦人的,如果非必要,直接把页面和后端置同域是个更好的选择
    个人认为 cors 跨域的场景应该是一些提供一些第三方公共资源
    xiaochong0302
        3
    xiaochong0302  
    OP
       Oct 20, 2020
    @eudore 是的,很多人都是一股脑的全部返回
    @KuroNekoFan 我的开发环境是 linux, 弄 app 用到了 uni-app,它的开发工具 hbuilder 又没有 linux 版本的,没办法在虚拟机里面搭了个 windows 环境
    renmu123
        4
    renmu123  
       Oct 20, 2020 via Android
    嫌麻烦其实可以直接找个跨域的中间件,配置什么也比较多,基本也不会出什么 bug
    356693212
        5
    356693212  
       Oct 20, 2020
    你这理论上也不对,*不能满足 cookie 携带的问题,勉强够用吧,等遇到问题再说吧
    raysonlu
        6
    raysonlu  
       Oct 20, 2020
    对比这种*号方案,在实际生产环境上,我觉得有仅仅支持二级域名跨域的方案,会有意义些。
    est
        7
    est  
       Oct 20, 2020
    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  
       Oct 20, 2020
    然后 add_header 还有个问题就是 rewrite 比如 http 升级 https 的不会带上,也会导致跨域失败。
    rrfeng
        9
    rrfeng  
       Oct 20, 2020   ❤️ 1
    你这相当于废掉了 CORS 。
    人家给你造了一把锁锁你家门,你直接把门拆了说我不要……还『正确方式』呢。
    xiaochong0302
        10
    xiaochong0302  
    OP
       Oct 20, 2020
    @356693212
    @raysonlu
    @est
    @rrfeng
    走的 API 请求,所以不用 COOKIE,上面只是示例,具体的要按自己的需求来调整

    自然是在后端代码里面支持更可控,nginx 也只是一个方案而已
    justseemore
        11
    justseemore  
       Oct 20, 2020
    更倾向于中间件.后端接口来控制..你这每次加个 origin 都要 reload 一次服务器..单机问题不大..集群的话会疯..
    PonysDad
        12
    PonysDad  
       Oct 20, 2020
    这样配置,那 CORS 还有啥子意义,来者不拒啊.
    bigNewsMaker
        13
    bigNewsMaker  
       Oct 20, 2020
    梭哈编程,能跑就行
    xiaochong0302
        14
    xiaochong0302  
    OP
       Oct 20, 2020
    已经在后端代码里做控制了,各位别再 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  
       Oct 20, 2020
    我是截取 Referer 和 Origin 两个来判断是否跨域,基本上 pc 端全兼容..
    ivanshaoaz
        16
    ivanshaoaz  
       Oct 20, 2020
    @xiaochong0302 #14 phalcon 啊
    xiaochong0302
        17
    xiaochong0302  
    OP
       Oct 20, 2020
    @ivanshaoaz 大佬,这都能看出来呀
    just1
        18
    just1  
       Oct 20, 2020
    如果你是问问题,那么你在代码里写了不告诉大家这没问题,反正解决了就好。
    你放个半吊子在这告诉大家是正确方式,还不说明,不 dui 你 dui 谁
    ivanshaoaz
        19
    ivanshaoaz  
       Oct 20, 2020
    @xiaochong0302 #17 我可不是大佬,最近在用 phalcon4 写项目
    fumichael
        20
    fumichael  
       Oct 21, 2020
    @est #8 我昨天用楼主的方案想代理 smms 的上传接口,结果失败了,还没弄清楚原因
    justseemore
        21
    justseemore  
       Oct 21, 2020
    在 dui 一下.. 你这 origin 多个时候不生效啊. 应该是配置那是数组判断是不是在数组,
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1023 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 63ms · UTC 22:27 · PVG 06:27 · LAX 15:27 · JFK 18:27
    ♥ Do have faith in what you're doing.