首页 > 解决方案 > 用于更改 request.url 的 VCL Snippet

问题描述

我正在尝试实现一个 VCL 片段(用于 Fastly Varnish 实现),它将在将请求代理到服务之前替换 URL。

例如。:

//domain.com/services/user/hello-world->//userservice/hello-world

为此,我写了这个:

      if (req.url.path ~ "^/services/") {
        set req.url = regsub(req.url, "/services/(.*?)/", "/");
      }

这应该在后端获取之前应用,这样它不会对缓存或其他条件产生任何影响。根据文档,这应该放在里面vcl_pass。那是对的吗?vcl_fetch似乎为时已晚。

这在 Fastly 设置中编辑为:

在此处输入图像描述

这会生成以下vcl_pass代码:https ://gist.github.com/knyttl/ae1a3afbc219e311ace3d7d305f9142d

但是,它不起作用,因为目标后端接收到完整的、未修改的 url。我究竟做错了什么?这样做是vcl_pass正确的阶段吗?

标签: varnishvarnish-vclfastly

解决方案


更新

好的,所以重新阅读原始发布者的问题,我意识到首先我误解了他们的要求,但后来我也注意到他们对 Kailan 回答的评论也略微调整了要求。

所以我的理解是现在的要求是......

  1. 根据传入的请求路径修改后端。
  2. 在不影响缓存的情况下修改传入请求路径(例如,原始请求路径将是缓存查找中使用的路径)。

例如,如果我们的默认后端是httpbin.org并且传入的请求是,/services/users那么我们希望后端更改为另一个后端(我们会说bbc.co.uk)。

但是我们也希望路径从/services/user/变为/,而bbc.co.uk后端的响应缓存在原始请求路径/services/users/ 下。

这是一个证明这一点的小提琴: https ://fiddle.fastlydemo.net/fiddle/e337b8f5

注意:您不能将字符串设置为的原因req.backend是因为它需要被分配一个特定的BACKEND类型

如果小提琴链接停止工作,代码如下......

vcl_recv

if (req.url.path ~ "^/services/user/" ) {
  // pretend www.bbc.co.uk is the correct backend for handling a 'user' request
  set req.backend = F_origin_1;
}

注意:后端分配给递增变量F_origin_0F_origin_1。所以在我的小提琴示例F_origin_0中是 httpbin.orgF_origin_1而是 bbc.co.uk

vcl_miss

if (req.url.path ~ "^/services/.*") {
  set bereq.url = "/";
}

我的原始答案

Kailan 的答案是正确的,应该这样标记,但为了完整起见,我将更加充实它,以便原始海报对正在发生的事情有更清晰的概念理解......

对 Varnish 的传入请求被转换为req通过各种状态/子例程传递的对象(例如vcl_recv== 收到请求,vcl_deliver== 请求已被处理,并且准备好将响应发送回客户端等)。

您的条件逻辑应该添加到子例程中,因为这是传入请求的第一个“状态”,也是您可以修改vcl_recv请求的最早点。

可以使用return(<state>)指令控制通过 Varnish 的请求对象的流程,该指令指示下一步要移动到什么状态。Varnish 具有默认行为,这意味着您不需要每个可用子例程结束时显式调用return(将为您调用一个将您的请求移动到下一个逻辑状态/子例程的决定),因此您决定显式更改默认值请求流的使用return将取决于您要执行的操作(在您的情况下,您无需担心这一点)。

一个典型/默认的请求流程会让请求对象从vcl_recv到移动,vcl_hash因此 Varnish 可以生成一个“查找”键(用于查找先前缓存的请求版本),然后取决于是否找到了请求的缓存版本请求将移动到vcl_miss(未找到缓存版本)或vcl_hit(找到缓存版本)。

如果没有缓存内容,那么在vcl_miss向您的后端/源服务器发出请求之后,来自后端的响应将vcl_fetch作为beresp对象提供给。最后,响应被传递到vcl_deliver您可以修改响应的位置,然后再将其发送回客户端。

request ( req) 对象通过所有这些状态/子例程传递,这意味着您可以在整个请求流程中的任何时候访问它。

如果您需要有关各种 VCL 子例程的更多指导(它们为什么存在,以及您可以在每个子例程中修改什么),那么请快速将它们全部记录在这里(以及一个漂亮的“请求流”图):https://developer .fastly.com/learning/vcl/using/


推荐阅读