varnish 4.0 官方文档翻译20-Device detection

Device detection

设备检测基于请求中的User-agent找出哪种内容返回给客户端。

使用Device detection情况的一个例子,发送给小屏幕的手机客户端或者复杂的网络环境,减少发送文件的数量,或者提供给不能解码的客户端一个video解码器。

有些使用这种方案的典型场景:

  • 重写url
  • 使用不同的后端给客户端
  • 改变后端请求为了让后端发送裁剪的内容

可能为了便于理解,下文中假定req.http.X-UA-Device头表示当前前客户端,同时每种客户端是唯一的。

简单的像这样设置头:

sub vcl_recv {
    if (req.http.User-Agent ~ "(?i)iphone" {
        set req.http.X-UA-Device = "mobile-iphone";
    }
}

不同的处理请求,同时免费提供组织和验证更详细的的客户端。基本且通用的是使用正则表达式来设置。查看https://github.com/varnish/varnish-devicedetect/

Serve the different content on the same URL

这个戏法表明:

  • 验证客户端(相当简单,只需要包含devicedetect.vcl,然后调用它)
  • 根据客户端的类型找出怎样发送请求到后端。这包含了些例子,设置header,改变header,甚至改变发送到后端的url。
  • 修改后端响应,增加miss标志‘Vary‘头。
  • 修改发送到客户端的输出,这样如果任何cache不受控,可以不提供错误的内容给客户端。

所有这些都需要确定我们每种设备只会获得一个缓存的对象。

Example 1: Send HTTP header to backend

基本情况是Varnish增加X-UA-Device头在发送到后端的请求上,然后后端在响应header中添加Vary头,响应的内容依赖发送到后端的header。

从Varnish角度看一切开箱即用。

VCL:

sub vcl_recv {
    # call some detection engine that set req.http.X-UA-Device
    # 调用一些检测机来设置req.http.X-UA-Device。
}
    # req.http.X-UA-Device is copied by Varnish into bereq.http.X-UA-Device
    # req.http.X-UA-Device 被复制到bereq.http.X-UA-Device,当请求传递到后端时。

    # so, this is a bit counterintuitive. The backend creates content based on
    # the normalized User-Agent, but we use Vary on X-UA-Device so Varnish will
    # use the same cached object for all U-As that map to the same X-UA-Device.
    #
    # 因此这是有点反直觉的。后端创建响应内容基于正常的User-Agent,但是在X-UA-Device使用
    # Vary,varnish将使用相同的已缓存的对象,对所有的U-As映射到相同的X-UA-Device。

    # If the backend does not mention in Vary that it has crafted special
    # content based on the User-Agent (==X-UA-Device), add it.
    # 如果基于User-Agent的后端响应不带有Vary,在header种增加它。

    # If your backend does set Vary: User-Agent, you may have to remove that here.
    # 如果后端设置了Vary:User-Agent,你可以在此删除它,或者设置成其他的。

sub vcl_backend_response {
    if (bereq.http.X-UA-Device) {
        if (!beresp.http.Vary) { # no Vary at all
            set beresp.http.Vary = "X-UA-Device";
        } elseif (beresp.http.Vary !~ "X-UA-Device") { # add to existing Vary
            set beresp.http.Vary = beresp.http.Vary + ", X-UA-Device";
        }
    }
    # comment this out if you don‘t want the client to know your
    # classification
    # 如果不想客户端知道你的分类,注释掉即可。
    set beresp.http.X-UA-Device = bereq.http.X-UA-Device;
}

# to keep any caches in the wild from serving wrong content to client #2
# behind them, we need to transform the Vary on the way out.
sub vcl_deliver {
    if ((req.http.X-UA-Device) && (resp.http.Vary)) {
        set resp.http.Vary = regsub(resp.http.Vary, "X-UA-Device", "User-Agent");
        # 在resp.http.Vary的值中将X-UA-Device替换为User-Agent。
    }
}

Example 2: Normalize the User-Agent string

标准化User-Agent字符。

另一种发送设备类型的目的是为了重写或者标准化发送到后端的User-Agent。

例如:

User-Agent: Mozilla/5.0 (Linux; U; Android 2.2; nb-no; HTC Desire Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

变成:

User-Agent: mobile-android

如果你在后端上不需要源http header的任何信息可以这样设置。一种可能性就是使用CGI脚本,只需小小设置下预定义的头信息在可以用的脚本中。

VCL:

sub vcl_recv {
    # call some detection engine that set req.http.X-UA-Device
}

# override the header before it is sent to the backend
# 发送到后端之前重写header。
sub vcl_miss { if (req.http.X-UA-Device) { set bereq.http.User-Agent = req.http.X-UA-Device; } }
sub vcl_pass { if (req.http.X-UA-Device) { set bereq.http.User-Agent = req.http.X-UA-Device; } }

# standard Vary handling code from previous(之前的) examples.
sub vcl_backend_response {
    if (bereq.http.X-UA-Device) {
        if (!beresp.http.Vary) { # no Vary at all
            set beresp.http.Vary = "X-UA-Device";
        } elseif (beresp.http.Vary !~ "X-UA-Device") { # add to existing Vary
            set beresp.http.Vary = beresp.http.Vary + ", X-UA-Device";
        }
    }
    set beresp.http.X-UA-Device = bereq.http.X-UA-Device;
}
sub vcl_deliver {
    if ((req.http.X-UA-Device) && (resp.http.Vary)) {
        set resp.http.Vary = regsub(resp.http.Vary, "X-UA-Device", "User-Agent");
    }
}

Example 3: Add the device class as a GET query parameter

以GET参数作为设备类型

上面两种方式都不行的话你可使用GET参数来增加设备类型。

http://example.com/article/1234.html --> http://example.com/article/1234.html?devicetype=mobile-iphone

客户端不会查看分类,仅仅是后端请求被修改了。

VCL:

sub vcl_recv {
    # call some detection engine that set req.http.X-UA-Device
}

sub append_ua {
    if ((req.http.X-UA-Device) && (req.method == "GET")) {
        # if there are existing GET arguments;
        if (req.url ~ "\?") {
            set req.http.X-get-devicetype = "&devicetype=" + req.http.X-UA-Device;
        } else {
            set req.http.X-get-devicetype = "?devicetype=" + req.http.X-UA-Device;
        }
        set req.url = req.url + req.http.X-get-devicetype;
        # 重写url
        unset req.http.X-get-devicetype;
        # 移除req.http.X-get-devicetype
    }
}

# do this after vcl_hash, so all Vary-ants can be purged in one go. (avoid ban()ing)
sub vcl_miss { call append_ua; }
sub vcl_pass { call append_ua; }

# Handle redirects, otherwise standard Vary handling code from previous
# examples.
sub vcl_backend_response {
    if (bereq.http.X-UA-Device) {
        if (!beresp.http.Vary) { # no Vary at all
            set beresp.http.Vary = "X-UA-Device";
        } elseif (beresp.http.Vary !~ "X-UA-Device") { # add to existing Vary
            set beresp.http.Vary = beresp.http.Vary + ", X-UA-Device";
        }

        # if the backend returns a redirect (think missing trailing slash),
        # we will potentially show the extra address to the client. we
        # don‘t want that.  if the backend reorders the get parameters, you
        # may need to be smarter here. (? and & ordering)

        if (beresp.status == 301 || beresp.status == 302 || beresp.status == 303) {
            set beresp.http.location = regsub(beresp.http.location, "[?&]devicetype=.*$", "");
        }
    }
    set beresp.http.X-UA-Device = bereq.http.X-UA-Device;
}
sub vcl_deliver {
    if ((req.http.X-UA-Device) && (resp.http.Vary)) {
        set resp.http.Vary = regsub(resp.http.Vary, "X-UA-Device", "User-Agent");
    }
}

Different backend for mobile clients

对手机客户端使用不同的后端。

如果对于手机客户端你有不同的后端来提供页面,或者在VCL种有任何特殊需求,你可以使‘X-UA-Device‘头像这样:

backend mobile {
    .host = "10.0.0.1";
    .port = "80";
}

sub vcl_recv {
    # call some detection engine

    if (req.http.X-UA-Device ~ "^mobile" || req.http.X-UA-device ~ "^tablet") {
        set req.backend_hint = mobile;
    }
}
sub vcl_hash {
    if (req.http.X-UA-Device) {
        hash_data(req.http.X-UA-Device);
    }
}

Redirecting mobile clients

如果想重定向手机客户端可以使用下面的代码片段:

sub vcl_recv {
    # call some detection engine

    if (req.http.X-UA-Device ~ "^mobile" || req.http.X-UA-device ~ "^tablet") {
        return(synth(750, "Moved Temporarily"));
    }
}

sub vcl_synth {
    if (obj.status == 750) {
        set obj.http.Location = "http://m.example.com" + req.url;
        set obj.status = 302;
        return(deliver);
    }
}

自己的例子

sub vcl_recv {
    if (req.http.host == "www.example.com" && req.http.User-Agent ~ "(?i)MIDP|WAP|UP.Browser|Smartphone|Obigo|Mobile|AU.Browser|wxd.Mms|WxdB.Browser|CLDC|UP.Link|KM.Browser|UCWEB|SEMC\-Browser|Mini|Symbian|Palm|Nokia|Panasonic|MOT|SonyEricsson|NEC|Alcatel|Ericsson|BENQ|BenQ|Amoisonic|Amoi|Capitel|PHILIPS|SAMSUNG|Lenovo|Mitsu|Motorola|SHARP|WAPPER|LG|EG900|CECT|Compal|kejian|Bird|BIRD|G900/V1.0|Arima|CTL|TDG|Daxian|DAXIAN|DBTEL|Eastcom|EASTCOM|PANTECH|Dopod|Haier|HAIER|KONKA|KEJIAN|LENOVO|Soutec|SOUTEC|SAGEM|SEC|SED|EMOL|INNO55|ZTE|iPhone|Android|Windows CE|Wget|Java|Opera") {
        set req.backend_hint = mobile;
        return(pass);
    }
}
时间: 2024-10-27 06:57:04

varnish 4.0 官方文档翻译20-Device detection的相关文章

varnish 4.0 官方文档翻译12-VCL

VCL - Varnish Configuration Language 本节包含了怎样通过varnish配置语言vcl来通知varnish如何处理http请求. varnish是高度结构化的系统.大多数其他的系统使用配置指令,在那里你基本上打开和关闭大量的开关.而我们选择使用领域特定语言,被叫做VCL,来完成之前的功能. 每个进入的请求流通过varnish,同时你可以支配如何通过VCL代码来处理请求.你可以让某些后端直接处理请求,你可以改变请求和响应,或者让varnish拥有各种各样动作依赖于

varnish 4.0 官方文档翻译-简要教程

varnish 4.0简要教程 这部分教程包含了varnish基本原理.囊括了什么是varnish.它怎样工作,同时也包含了开始使用和运行varnish.这部分过后你可能想继续了解用户向导(varnish用户引导). 如果你正在web上读这些呢 注意每页左边的Next topic和Previous topic The fundamentals of web proxy caching with Varnish使用varnish作为web代理缓存的原理 Supported platforms 支持

varnish 4.0 官方文档翻译21-Reporting and statistics

Reporting and statistics 本部分包括如何查看Varnish正在做什么,从每个http请求流的详细记录到汇总统计计数器. Logging in Varnish Statistics varnishtop varnishhist varnishstat Logging in Varnish Varnish中一个很棒的特点是工作日志的记录方式.varnish不记录日志到日志文件,而是调用VSL记录到共享内存片段,VSL-varnish共享日志.当这个片段被写完后,varnish

varnish 4.0 官方文档翻译22-Varnish Website Performan

Varnish and Website Performance 本节集中解决如何调优varnish server,同时如何使用varnish优化你的web站点. 一共有三小节.第一小节你应该想到varnish的各种工具和功能,下一小节如何从cache中清除已经缓存的内容.清除内容是一项基本功能,因为它允许给缓存的对象增加 TTL.TTL越大varnish保持在缓存中的时间越久,这意味着varnish处理更多的请求,只将少部分的请求传递到相对较慢的后端. 最后一小节,处理web内容的压缩.当从后端

varnish 4.0 官方文档翻译7-用户手册-安全第一

Security first 安全第一 如果你仅仅抓专注于运行varnish,或者所有人都是这个观点,那么就可以跳过该节了.我们保护你的方方面面当http请求来的时候. 如果你的web基础设施是外包的,管理是分开的,那么你就需要考虑安全了. Varnish在4个权威的等级提供安全,大致关系到怎样让命令生效和在哪儿生效. the command line arguments, the CLI interface, VCL programs, and HTTP requests. Command l

varnish 4.0 官方文档翻译19-VCL Examples

VCL Examples Manipulating request headers in VCL 在VCL中操作请求的header. 当我们想移除发送到web服务器/images目录的所有对象的cookie可以这样: sub vcl_recv {     if (req.url ~ "^/images") {     unset req.http.cookie;     } } 这样当请求被后端处理时在http的header中将不再有cookie信息.有用的是使用if语句.在匹配的UR

varnish 4.0 官方文档翻译7-用户手册-重要命令行参数

重要的命令行参数 当启动varnish时有两个重要的参数你必须设置: 一个是处理http请求的tcp监听端口,另一个是处理真实请求的后端server 如果你使用操作系统自带的包管理工具安装的varnish,你将在下面的文件找到启动参数: Debian, Ubuntu: /etc/default/varnish Red Hat, Centos: /etc/sysconfig/varnish FreeBSD: /etc/rc.conf (See also: /usr/local/etc/rc.d/v

varnish 4.0 官方文档翻译9-用户手册- 向Vanish下发指令

CLI-bossing Varnish around CLI 向Vanish下发指令 一旦vanish启动,你可以使用命令行接口来控制它. 最轻松的使用CLI的方法是在运行varnishd的机器上运行,varnishadm varnishadm help 如果你想远程使用varnishadm,有两种方法. 你可以使用ssh登录到运行varnishd的机器上然后varnishadm ssh $http_front_end varnishadm help 同时你也可以配置vanishd接受远程的CL

varnish 4.0 官方文档翻译16-Backend servers/M/B/D/H

Backend servers varnish有"后端"或者"源"服务器的概念.backend server提供给varnish加速的内容. 第一步设置是告诉varnish从哪儿找到backend server.使用你喜欢的编辑器打开varnishd引入的VCL文件. VCL文件的开头有一小段有点像这样: # backend default { #     .host = "127.0.0.1"; #     .port = "8080