使用Varnish缓存清空POST请求


Empty POST requests with Varnish cache

所以我在html/php中有一个非常简单的登录表单

login1.php

<?php include('settings.php'); ?>
<!DOCTYPE html>
<html>
<head>
    <title>login</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
    <form id="form1" name="form1" method="post" action="<?=$basehttp;?>/login_auth1.php">
    <input name="ahd_username" type="text" id="ahd_username" size="35" maxlength="255" />
    <input name="ahd_password" type="password" id="ahd_password" size="35" maxlength="35" />
    <input type="submit" name="Submit" value="Login" />
    </form>
</body>
</html>

login_auth1.php

<?php
include('settings.php'); 
print_r($_POST);
print_r(getallheaders());
if(isset($_POST['ahd_username']) && isset($_POST['ahd_password'])){
  //database queries and stuff, send user elsewhere if login correct
}
?>
<!DOCTYPE html>
<html>
<head>
    <title>login</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
    <form id="form1" name="form1" method="post" action="<?=$basehttp;?>/login_auth1.php">
    <input name="ahd_username" type="text" id="ahd_username" size="35" maxlength="255" />
    <input name="ahd_password" type="password" id="ahd_password" size="35" maxlength="35" />
    <input type="submit" name="Submit" value="Login" />
    </form>
</body>
</html>

当运行login1.php(在某些web浏览器中)时,login_auth1.php中的POST将为空。但是,当再次从login_auth1.php提交完全相同的表单时,它运行得很好。这个错误的原因可能是什么?如何进一步调试?仅供参考服务器正在运行Varnish。

在这个文本文件中可以找到一些调用的带有标题的输出链接。

编辑:现在我头上已经没有头发了,但我已经找到了一种"有效"的方法。如果我将我的登录文件合并到一个文件中,将该文件放在一个单独的文件夹/登录中,完全删除操作标记中的url(因此它将是action="),并将Varnish配置为

if (req.url ~ "/login"){
  set req.backend = mybackend;
  return (pass);
}

它会起作用的。这感觉像是一个非常糟糕的"解决方案",尤其是删除动作标签中的字符串的部分,但这是我实现它的唯一方法。我试过很多不同的清漆配置,包括回流(管道)。有人知道如何让它正常工作吗?或者为什么上面这个奇怪的版本有效?

一个好而持久的做法,取代你的快速破解,就是不缓存任何帖子请求:

if ( req.request == "POST" ) {
   return (hit_for_pass);
}

Varnish的标准行为[1](至少在3.0中,debian)是将POST请求直接传递到后端:

sub vcl_recv {
#...
  if (req.request != "GET" && req.request != "HEAD") {
    /* We only deal with GET and HEAD by default */
    return (pass);
  }
#...
}

因此,如果未达到默认代码(您在vcl_recv中调用return(xxx)),则应在自己的vcl代码中处理此类请求,按照Clarence的建议返回pass或hit_for_pass。

[1]https://www.varnish-cache.org/docs/3.0/reference/vcl.html#examples