nginx - 基于referer的nginx条件路由

标签 nginx nginx-reverse-proxy nginx-config

我需要根据 http 请求来源路由流量。我有两个环境,我们需要使用“$http_referer”将“/us-en”的每个 http 请求重定向到 Environment1,将其他请求重定向到 Environment2。

  • 基于位置的重定向工作。
  • location ~ /us-en { 
        proxy_pass Environment1; 
        proxy_set_header Host Environment1; 
    } 
    
  • 使用 '$http_referer' 以下选项不起作用。请求您的建议。
  • if ($http_referer ~ ^https?://dev.xyz.com/us-en){ 
        rewrite ^/us-en(/*)$ HOME_PAGE$1 break; 
        proxy_pass Environment1; 
    }
    Error: nginx: [emerg] "proxy_pass" directive is not allowed here in /opt/nginx/conf/nginx.conf.
    

    注意:默认情况下,所有流量都进入 Environment2,因为存在上游配置。

    最佳答案

        # needed if your proxy destination specified with domain name instead of IP address
        resolver 8.8.8.8;
    
        location /home/ {
            proxy_set_header Host HOST1;
            # setup other proxied headers if needed
            if ($http_referer ~ ^https?://dev.xyz.com/home) {
                rewrite ^/home(/.*)$ HOME_PAGE$1 break;
                proxy_pass https://HOST1:8080; # this can be specified by IP address
            }
        }
    
    使用这样的配置请求从 your_domain.com/home/path/filedev.xyz.com/home/... (但不是从 dev.xyz.com/any/other/path !)将被代理到 https://HOST1:8080/HOME_PAGE/path/file 。如果您使用域名而不是 IP 地址指定代理目标,则需要在服务器配置中指定附加参数 resolver 。如果您有本地名称服务器,您可以使用本地名称服务器,也可以使用外部名称服务器,例如 Google 公共(public) DNS (8.8.8.8) 或 ISP 为您提供的 DNS。无论如何,这样的配置会导致额外的 DNS 查找,因此如果可以,请使用 IP 地址指定代理目标。
    更新
    使用 valid_referers 指令还有另一种方法:
        # needed if your proxy destination specified with domain name instead of IP address
        resolver 8.8.8.8;
    
        location /home/ {
            proxy_set_header Host HOST1;
            # setup other proxied headers if needed
            valid_referers example.com/home;
            if ($invalid_referer = "") {
                rewrite ^/home(/.*)$ HOME_PAGE$1 break;
                proxy_pass https://HOST1:8080; # this can be specified by IP address
            }
        }
    
    更新@2020.11.11
    除了这个答案以某种方式获得了 5 分之外,给定的解决方案的设计非常糟糕(在 location 和嵌套的 if block 中具有不同的内容处理程序不是一个好方法;此外,具有任何其他指令的 if block 如果可能的话,应该避免从 nginx rewrite module 开始)并且在早期的 nginx 版本上根本不起作用(当我看到我的一些早期答案时,我想哭)。一个原始的OP问题是

    The logic should be like below but has some syntax mistakes.

    if ($http_origin ~ '^http?://(dev.xyz.com/home)') {
        set $flag 'true';
    }
    
    if ($flag = 'true') {
        location /home/ {
            proxy_pass  "https://HOST1:8080/HOME PAGE/";        
        }
    }else{
        Do Not proxy pass
    }
    

    目前还不清楚不代理通行证是什么意思。如果它意味着返回一些 HTTP 错误(例如,HTTP 403 Forbidden),可以通过以下配置完成:
    location /home/ {
        if ($http_referer !~ ^https?://dev.xyz.com/home) {
            return 403;
        }
        rewrite ^/home(/.*)$ HOME_PAGE$1 break;
        proxy_set_header Host HOST1;
        # setup other proxied headers if needed
        proxy_pass https://HOST1:8080; # this can be specified by IP address
    }
    
    如果不代理传递意味着在本地服务请求,则解决方案更复杂:
    map $http_referer $loc {
        ~^https?://dev.xyz.com/home    loc_proxy;
        default                        loc_local;
    }
    
    server {
        ...
        location /home/ {
            try_files /dev/null @$loc;
        }
        location @loc_proxy {
            rewrite ^/home(/.*)$ HOME_PAGE$1 break;
            proxy_set_header Host HOST1;
            # setup other proxied headers if needed
            proxy_pass https://HOST1:8080;
        }
        location @loc_local {
            rewrite ^/home(/.*)$ HOME_PAGE$1 break;
            root /path/to/required/page;
            ...
        }
    
    try_files /dev/null @the_named_location; 技巧取自 this 优秀答案。
    然而,现在已编辑的 OP 的问题说明了不同的要求,这也可以通过 map 指令帮助来实现:
    map $http_referer $environment {
        ~^https?://dev.xyz.com/home    Environment1;
        default                        Environment2;
    }
    
    server {
        ...
        location /home/ {
            rewrite ^/home(/.*)$ HOME_PAGE$1 break;
            proxy_set_header Host $environment;
            # setup other proxied headers if needed
            proxy_pass https://$environment;
        }
    

    关于nginx - 基于referer的nginx条件路由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53718930/

    相关文章:

    linux - 为 PHP-FPM 配置 IPtables

    php - 将请求从 Nginx 代理到 HHVM 时自定义 header 或查询字符串?

    nginx - 使用 nginx 作为反向代理与 keycloak 作为上游服务器的组合失败

    http - 合并两个 nginx 服务器

    nginx - 主机的 Kubernetes Ingress 白名单 IP

    nginx - Nexus (3.2) 基本 URL 被忽略?

    http - 如何在HTTPS网页中显示HTTP内容

    docker - nginx反向代理简单配置不重定向

    api - 如何动态获取 NGINX 代理的 API 访问 token

    nginx - 需要来自 Nginx 的证书链(在传入接口(interface)上)