3-4-9-HAProxy高级功能与配置之重定向

熊 0 阅读 Linux集群服务


关于
Hproxy请求重定向主要会用到: redirect 和 redir 这两类重定向配置语法。

  • redirect重定向用法: redirect通常配置在haproxy acl部分

    redirect一般有两个指令来执行HTTP重定向 :

    • http-requets redirect : 此种方式支持日志变量格式

    • redirect : 此种方式只依赖于静态字符串

    这两个指令的语法是相同的 , 即redirect现在被认为是传统和配置应该移动到http-request redirect形式。 还有一个主要区别是 : http-request redirect使用日志可变格式 , 而redirect语句只依赖于静态字符串。

1 redirect三种重定向方式

  • 位置重定向

    redirect location <loc> [code <code>] <option> [{if | unless} <condition>]

    使用位置重定向 , 例如下面所示指令可以将用户重定向到所提供的精确位置 , 该位置可以是第三方URL链接 , 也可以是本地web 服务的另一个访问路径.

    http-request redirect location <loc> [code <code>] [<option>] [<condition>]
    redirect location <loc> [code <code>] [<option>] [<condition>]
    • <loc> : 一个日志格式变量 (或简单的字符串redirect语句)描述了新位置 ;

    • code <code>(可选) : HTTP重定向的状态代码来执行。 此选项下的允许的状态码如下所示

    • <option> (可选): 可以是以下任何或组合的声明

      set-cookie NAME[=value] :一个Set-Cookie头部被添加到重定向。该cookie被命名为名称 ,可以有一个可选的值。

      clear-cookie NAME[=]一个特殊的Set-Cookie头被添加到重定向。该Cookie名为名称和最大年龄的cookie参数设置为0 , 目的是为了指示浏览器删除cookie。

      注意: 在于浏览器中 , 这是两个不同的Cookie:NAME和NAME = 以上根据您的流量模式 , 必须将两个语句适应。

    • if | unless : 用于条件判断

    • <condition> (可选) : 用于匹配acl , 一般为acl的名称

  • 前缀重定向

    redirect prefix <loc> [code <code>] <option> [{if | unless} <condition>]

    使用前缀重定向 , 将用户重定向到由concateneting建立了一个网址<pfx>和完整的原始URI路径:

    http-request redirect prefix <pfx> [code <code>] [<option>] [<condition>]
    redirect prefix <pfx> [code <code>] [<option>] [<condition>]
    • <pfx> : 一个日志格式变量 (或简单的字符串redirect语句)描述了新的位置前缀。

    • code <code>(可选) : HTTP重定向的状态代码来执行。 此选项下的允许的状态码如下所示

    • <option>(可选): 可以是以下任何或组合的声明

      • drop-query : 在执行串联时从原来的URL删除查询字符串

      • append-slash : 配合使用drop-query , 在该URL的末尾添加一个“/”字符

      • set-cookie NAME[=value] : 一个Set-Cookie头部被添加到重定向。该cookie被命名为名称 , 可以有一个可选的值。

      • clear-cookie NAME[=] : 一个特殊的Set-Cookie头被添加到重定向。该Cookie 名为名称和最大年龄的cookie参数设置为0 , 目的是为了指示浏览器删除cookie。

    • if | unless : 用于条件判断

    • <condition> : 用于匹配acl , 一般为acl的名称

  • 协议重定向

    redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]

    使用位置重定向 , 例如下面所示指令可以将用户重定向到所提供的新的http协议url链接 , 一般用于非安全链接跳转到安全链接 , 比如http跳转到https上

    http-request redirect scheme <schloc> [code <code>] [<option>] [<condition>]
    redirect scheme <sch> [code <code>] [<option>] [<condition>]
    • <sch>/<schloc> : url(<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>)中 , scheme部分

    • code <code>(可选):HTTP重定向的状态代码来执行。 此选项下的允许的状态码如下所示:

    • <option>(可选): 可以是以下任何或组合的声明

      • set-cookie NAME[=value] :一个Set-Cookie头部被添加到重定向。该cookie被命名为名称, 可以有一个可选的值值。

      • clear-cookie NAME[=]一个特殊的Set-Cookie头被添加到重定向。该Cookie名为名称和最大年龄的cookie参数设置为0 ,目的是为了指示浏览器删除cookie。

        注意: 在于浏览器中 , 这是两个不同的Cookie:NAME和NAME = 以上根据您的流量模式 , 必须将两个语句适应。

    • if | unless : 用于条件判断

    • <condition> (可选) : 用于匹配acl , 一般为acl的名称

示例

acl clear      dst_port  80
acl secure     dst_port  8080
acl login_page url_beg   /login
acl logout     url_beg   /logout
acl uid_given  url_reg   /login?userid=[^&]+
acl cookie_set hdr_sub(cookie) SEEN=1
 
redirect prefix   https://kevin.com set-cookie SEEN=1 if !cookie_set
redirect prefix   https://kevin.com           if login_page !secure
redirect prefix   http://kevin.com drop-query if login_page !uid_given
redirect location http://kevin.com/           if !login_page secure
redirect location / clear-cookie USERID=      if logout

2. redir重定向用法

使用redir会将发往backend的站点服务请求均以302状态响应发给需要重定向的server服务或站点 , 此时haproxy不需要向后端web server提交请求 ; 需要注意的是 , 在prefix后面不能使用/ , 且不能使用相对地址 , 以避免造成循环 , 例如:

frontend  main *:80
    default_backend app
backend app
    balance roundrobin
    server node1 127.0.0.1:81 check weight 3 redir http://www.kevin.com

上面配置含义:所有发往localhost:80的请求做重定向 , 重定向到www.kevin.com因此可以实现单台服务器的重定向

frontend  main *:80
    default_backend  app
backend app
    balance roundrobin
    server node1 127.0.0.1:81 check weight 3 redir http://www.grace.com

redir只做跳转 , 如客户端输入:http://ip,将会跳转到指定的页面上 , 此时客户端的页面也会跳转到指定的页面上 ,之后所有的请求都会递交到该站点(前提该站点可以与客户端通讯) , 而不再发往haproxy代理站点 , haproxy也不需要往后端web server提交客户端发过来的请求。

3. errorfile/errorcode 自定义错误页面

对指定的报错进行重定向 , 进行优雅的显示错误页面。

  • haproxy自定义错误页面有两种方式

    1. 一种是由haproxy本机提供错误页面 , 通过errorfile参数来设定。

    2. 第二种是将错误转到一个指定的url地址 通过 errorcode 参数来设定

3.1 基于错误页面文件

  • 语法 : errorfile <code> <file> 。返回文件内容而不是由HAProxy产生的错误。section : default、frontend、listen、backend。

    • <code> : HTTP状态码。目前 , HAProxy能够生成代码: 200, 400, 401, 403, 404, 405, 407, 408, 410,413,425, 429, 500, 501, 502,503, 504

    • <file> : 指定了一个包含完整HTTP响应的文件。建议遵循通常的做法 ,在文件名后面加上".http" , 这样人们就不会把响应与HTML错误页面混淆 ; 并使用绝对路径 , 因为在执行任何chroot之前都会读取文件。

errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorfile 408 /dev/null  # work around Chrome pre-connect bug
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
​
​
------------------------------
defaults
#option forwardfor
#no option http-use-htx
#...... #以下三行
errorfile 500 /usr/local/haproxy/html/500.html
errorfile 502 /usr/local/haproxy/html/502.html
errorfile 503 /usr/local/haproxy/html/503.html
​

3.2 基于http重定向

  • 语法 : errorloc <code> <url> / errorloc302 <code> <url>。返回一个HTTP重定向到一个URL , 而不是由HAProxy产生的错误。section : default、frontend、listen、backend。

    • <code> : HTTP状态码。目前 , HAProxy能够生成代码: 200, 400, 401, 403, 404, 405, 407, 408, 410,413,425, 429, 500, 501, 502,503, 504

    • <uri> : 他是Location头部指定的跳转uri。它可以包含一个相对的URI , 指向同一网站上的错误页面 , 或者一个绝对的URI , 指定另一个网站上的错误页面。应该特别注意相对URI , 以避免重定向循环 , 如果URI本身可能产生相同的错误(如500)

这两个关键词都会返回HTTP 302状态代码 ,它告诉客户端使用相同的HTTP方法来获取指定的URL。在非GET方法(如POST)的情况下 , 这可能是相当有问题的 ,因为发送到客户端的URL可能不允许使用GET以外的方法。为了解决这个问题 , 请使用 "errorloc303 "来发送HTTP 303状态代码 , 向客户端表明该URL必须用GET请求获取。

  • 语法: errorloc303 <code> <url> : 返回一个HTTP重定向到一个URL , 而不是由HAProxy产生的错误。这两个关键词都会返回HTTP 303状态代码 ,它告诉客户端使用相同的HTTP GET方法来获取指定的URL。这就解决了与 "errorloc"和302代码有关的通常问题。有可能一些在HTTP/1.1之前设计的非常老的浏览器不支持它 , 但到目前为止还没有这样的问题报告。

defaults
#option http-keep-alive
#option forwardfor
#no option http-use-htx
#...... 以下一行
errorloc 503 http://192.168.7.102/error_page/503.html

4. 重定向示例

  • 示例1

    1) 首先每个域名解析到自己的ip
    www.kevin.com   172.16.51.100
    www.grace.com   172.16.51.200
    www.bobo.com    172.16.51.210
     
    2) 域名重定向
    acl name_redirectA hdr_beg(host) -i www.kevin.com
    redirect prefix http://www.bobo.com/A if name_redirectA
     
    acl name_redirectB hdr_beg(host) -i  www.grace.com
    redirect prefix http://www.bobo.com/B if name_redirectB
     
    3) 跳转规则
    acl name_A hdr_beg(host) -i www.kevin.com
    acl name_B hdr_beg(host) -i www.grace.com
    acl name_C hdr_beg(host) -i www.bobo.com
    acl api_reqA path_beg -i /A/api
    acl api_reqB path_beg -i /B/api
    use_backend appserver_8081 if name_A or name_B      #匹配"或"的规则
    use_backend appserver_8082_A if name_C api_reqA     #匹配"和"的规则
    use_backend appserver_8082_B if name_C api_reqB      
     
    backend appserver_8081
       balance source
       server web1 172.16.51.171:8081 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
       server web2 172.16.51.174:8081 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
     
    backend appserver_8082_A
       server web1 172.16.51.180:80 weight 3 check inter 2000 rise 2 fall 3
      
    backend appserver_8082_B
       server web1 172.16.51.180:80 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
  • 示例2

    redirect location <to> [code <code>] <option> [{if | unless} <condition>]
    redirect prefix <to> [code <code>] <option> [{if | unless} <condition>] 重定向 , 相当于rewrite
      
    示例配置如下:
    acl shibo hdr_reg(host) -i ^(shibo.kevin.com|forum.kevin.com)       #使用正则匹配
    acl shibo_path path_beg -i /shibo                #url 目录
    acl youxi path_beg -i /youxi              
    acl static path_end -i .html .css .js      #url 结尾文件
    acl php path_end -i .php 
    acl jsp path_end -i .jsp .do 
      
    use_backend shibo_pool if shibo or shibo_path       #注意"或"的匹配用"or"
    use_backend youxi_pool if youxi
    use_backend static_pool if static 
    use_backend php_pool if php
    use_backend jsp_pool if jsp
    default_backend www.kevin.com                
     
    #当满足host_bb.cn的策略,跳转(重定向)到http://www.bb.cn
    acl host_bb.cn hdr_beg(host) -i (bb.cn|beijing.com)
    redirect prefix http://www.bb.cn if host_bb.cn
      
    #有个问题: haproxy能否在接到一个请求时选择一个后端服务器 , 然后301重定向url 。
    #主要原因是他有5个1G的出口 , 这样就能充分利用其带宽。
    #测试了一下是可以的
    frontend free
       bind *:80
       default_backend lvs2
    backend lvs2
       mode http
       option forwardfor header ORIG_CLIENT_IP
       server free174 172.16.51.16:8081 redir http://free71-174-grace.com:8081 weight 10 rise 3 fall 5 check inter 2000
       server free173 172.16.51.15:8081 redir http://free71-173-grace.com:8081 weight 10 rise 3 fall 5 check inter 2000
           
    #当输入负载均衡机器的域名后 , url会直接变成http://free71-17(3|4)-grace.com:8081.
      
    acl monitor hdr_beg(host) -i monitor.kevin.com        #定义ACL名称(monitor),对应的请求的主机头是monitor.kevin.com 
    acl shibo hdr_reg(host) -i ^(shibo.kevin.com|forum.kevin.com)  #使用正则匹配
    acl host_bb.cn hdr_beg(host) -i bb.cn
    acl host_hui.cn hdr_beg(host) -i beijing.com
    redirect prefix http://www.bb.cn if host_bb.cn
    redirect prefix http://www.bb.cn if host_hui.cn
      
    frontend localhost
        bind *:80
        bind *:443 ssl crt /etc/ssl/bb.web/bb.web.pem
        redirect scheme https if !{ ssl_fc }
        mode http
        default_backend nodes
     
    # 上面配置中, 添加了redirect导向 , 如果连接不是通过SSL连接的 , 它将http重定向到https
      
    acl host_bb.cn hdr_beg(host) -i bb.cn
    acl host_jiu.cn hdr_beg(host) -i beijing.com
    acl www_jiu.cn hdr_beg(host) -i www.beijing.com
    acl host_hui.cn hdr_beg(host) -i pp.com
    acl www_hui.cn hdr_beg(host) -i www.pp.com
    redirect prefix http://www.bb.cn if host_bb.cn
    redirect prefix http://www.bb.cn if host_jiu.cn
    redirect prefix http://www.bb.cn if www_jiu.cn
    redirect prefix http://www.bb.cn if host_hui.cn
    redirect prefix http://www.bb.cn if www_hui.cn
      
    访问bb.cn,beijing.com,www.beijing.com,pp.com,www.pp.cpm 都跳转到http://www.bb.cn
  • 示例3

    • 需求如下

      1. 转发所有手机请求

        所有通过手机端访问http.shibo.com域名的话 , 全部转发到http://www.shibo.com这个地址 , 而PC端不受此限制。

      2. 根据url进行转发 如果手机端请求http.shibo.com这个域名的url中 , 以docs或者manager这两个关键词开头的话 , 把该请求转发到后端的服务器 , 而PC端不受此限制

      3. 也就是说手机端访问具体的url地址的话 , 可以正常访问。如果是直接访问http.shibo.com域名的话 , 直接把该请求转发到http://www.shibo.com 这个地址。

    • 配置

      [root@localhost ~]# vim /usr/local/haproxy/conf/haproxy.cfg
      global
         log 127.0.0.1 local0
         log 127.0.0.1 local1 notice
         maxconn 4096
         uid 188
         gid 188
         daemon
         tune.ssl.default-dh-param 2048
       
      defaults
         log global
         mode http
         option httplog
         option dontlognull
         option http-server-close
         option forwardfor except 127.0.0.1
         option redispatch
         retries 3
         option redispatch
         maxconn 2000
         timeout http-request 10s
         timeout queue 1m
         timeout connect 10s
         timeout client 1m
         timeout server 1m
         timeout http-keep-alive 10s
         timeout check 10s
         maxconn 3000
       
      listen admin_stats
         bind 0.0.0.0:1080
         mode http
         option httplog
         maxconn 10
         stats refresh 30s
         stats uri /stats
         stats auth admin:admin
         stats hide-version
       
      frontend weblb
         bind *:80
         acl is_http hdr_beg(host) http.shibo.com
         acl ua hdr_sub(user-agent) -i android iphone
         redirect prefix http://www.shibo.com if ua
         use_backend httpserver if is_http
       
      backend httpserver
          balance source
          server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
       

      在以上配置文件中 , 有以下两行需要注意:

      acl ua hdr_sub(user-agent) -i android iphone
      redirect prefix http://www.shibo.com if ua

      这两行: 第一行是第一个ua规则 , 该规则是判断是否是手机端。 注意:在此手机端 , 我们只匹配了安卓手机和iphone。 第二行是跳转规则 , 如果匹配是手机端的话 , 那么直接跳转到http://www.shibo.com这个地址。

    • 如果有两个域名的话 , 就要进行如下配置

      frontend weblb
         bind *:80
         acl is_http hdr_beg(host) http.shibo.com
         acl is_haproxy hdr_beg(host) haproxy.shibo.com
         acl ua hdr_sub(user-agent) -i android iphone
         redirect prefix http://www.shibo.com if ua !is_haproxy
         use_backend haproxyserver if ua is_haproxy
         use_backend haproxyserver if is_haproxy
         use_backend httpserver if is_http
       
      backend httpserver
         balance source
         server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
       
      backend haproxyserver
         balance source
         server web1 127.0.0.1:7070 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
    • 根据url进行转发配置

      frontend weblb
         bind *:80
         acl is_http hdr_beg(host) http.shibo.com
         acl is_docs url_beg /docs /manager
         acl ua hdr_sub(user-agent) -i android iphone
         redirect prefix http://www.shibo.com if ua !is_docs
         use_backend httpserver if ua is_docs
         use_backend httpserver if is_http
       
      backend httpserver
         balance source
         server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
      • acl is_docs url_beg /docs /manager 定义一个is_docs规则。如果url以/docs或者/manager开头的 , 则全部属于该规则。

      • acl ua hdr_sub(user-agent) -i android iphone redirect prefix http://www.shibo.com if ua !is_docs 这两行首先是匹配出手机端 , 然后如果是手机端访问 , 并且访问的不是is_docs规则的话 , 则直接跳转到http://www.shibo.com这个地址。

      • use_backend httpserver if ua is_docs 这条命令是 , 如果是手机端访问 , 并且访问的是is_docs规则的话 , 则直接跳转到httpserver这个后端服务器组。

      • 如果是PC端的话 , 默认跳转到httpserver这个后端服务器组。

    • 所有手机端访问的http.shibo.com , 转到指定的页面

      frontend weblb
         bind *:80
         acl is_http hdr_beg(host) http.shibo.com
         acl ua hdr_sub(user-agent) -i android iphone
         redirect prefix http://www.shibo.com/?p=10624 if ua
         use_backend httpserver if is_http
       
      backend httpserver
         balance source
         server web1 127.0.0.1:8080 maxconn 1024 weight 3 check inter 2000 rise 2 fall 3
         
      #以上配置是所有手机端访问的 , 都跳转到http://www.shibo.com/?p=10624这个页面。
  • 示例4

    • 访问https://www.shibo.com/guo-hui重定向跳转到 https://www.xiaobo.com/an-hui

      frontend https
          option http-server-close
          reqadd X-Forwarded-Proto:\ https
       
          acl shi_bo hdr(host) -i www.shibo.com
          acl guo_hui path_beg /guo-hui
          acl an_hui path_beg /an-hui
       
          reqirep ^([^\ ]*\ /)guo-hui(.*) \1an-hui\2 if shi_bo guo_hui         #注意中间的空格, 以及\1 和 \2;
          redirect prefix https://www.xiaobo.com code 301 if shi_bo an_hui