真的难倒了,因为形式和语法看起来都很好。
RewriteCond for REQUEST_URI 与显式路径和文件名不匹配。 隔离后,重写Cond for REQUEST_FILENAME匹配就好了。 我已经使用 phpinfo() 验证REQUEST_URI包含前导斜杠,并且也测试了没有前导斜杠。
这里的目标是知道请求是针对此文件的,如果它不存在,则抛出 410。
RewriteCond %{REQUEST_URI} ^/dir1/dir2/dir3/v_9991_0726dd5b5e8dd67a214c0c243436d131_all.css$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ - [R=410,L]
我不想省略第一个 Cond,因为我只想对与这个类似的少数文件执行此操作。
更新一
试图进行明确的测试。 测试设置:
- Testmee.txt 不存在
- 请求是针对 testmee.txt 在根目录中
- 通过重定向到谷歌来验证request_uri是否匹配
- 仅使用第一个 Cond 时无法获得 410
- (仅使用第一个 Cond 时,服务器为 404 提供服务,而不是 410)
- (同时使用两个 Conds,服务器为 404 提供服务,而不是 410)
- 仅使用第二个 Cond 时可以获得 410
RewriteCond %{REQUEST_URI} ^/testmee.txt$
#RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ - [R=410,L]
对
#RewriteCond %{REQUEST_URI} ^/testmee.txt$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ - [R=410,L]
更新二
对怀特先生的回应:
呃,同样的症状。 可能不得不忍受谷歌机器人达到404,而不是过时的css/js所需的410。 从长远来看,可能没什么大不
了的。感谢您request_uri测试重定向。 在这些测试中,一切正常。 页面名称等按预期在 var= 重写 URL 中返回。
在这一点上,我认为一定是与文件类型扩展名相关的 404 的一些内部处理。 请参阅下面的线索。 我有Prestashop购物车软件,它必须强制使用404文件类型。
这将重定向到谷歌(以确认模式匹配):
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^testmee.txt$ http://www.google.com/ [L]
(L flag is needed or else other Rules further down will interfere.)
这将继续返回 404 而不是 410:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^testmee.txt$ - [NC,R=410]
作为对照测试,这将返回 410:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*$ - [NC,R=410]
如果在上述失败的测试中文件类型为 css,则不会调用我的自定义 404 控制器。 我只是得到一个普通的 404 响应,没有用我所有网站模板包装的自定义 404。
例如:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^testmee.css$ - [NC,R=410]
恐怕我浪费了你的一些时间。 我道歉。 我从没想过 Prestashop 的代码会根据文件类型强制使用 404,但我看不到任何其他解释。 我可以深入研究它,也许可以在控制器中找到正在这样做的地方。 不过,得休息一下。
这不是一个可靠的答案,更多的是试图帮助调试它并消除一些神话......
我已经使用
phpinfo()
验证REQUEST_URI
包含前导斜杠
是的,REQUEST_URI
Apache 服务器变量确实包含前导斜杠。它包含完整的 URL 路径。
但是,REQUEST_URI
Apache 服务器变量不一定与$_SERVER['REQUEST_URI']
PHP 超全局变量相同 - 事实上,它们根本不是一回事。这些变量之间存在一些显着差异(在某些方面,它们共享相同的名称可能有点不幸)。值得注意的是,PHP 超全局包含来自请求的初始 URL,并包含查询字符串(如果有),并且没有 % 解码。而同名的 Apache 服务器变量包含重写的 URL(不一定是请求的URL),并且不包含查询字符串并且是 % 解码的。
所以,这就是为什么我问你是否有其他mod_rewrite指令。你很可能有冲突。如果另一个指令重写了 URL,那么条件将永远不会匹配(尽管 PHP 超全局建议它应该匹配)。
似乎如果我把它放在顶部,最后一个标志将结束该行程的处理,返回 410
此指令当然应该放在.htaccess
文件的顶部,以避免 URL 被更早重写。当与R=410
(除3xx
以外的任何东西)一起使用时,L
标志实际上是多余的 - 在这种情况下是隐含的。
然后我将结果更改为"抛出 410",它抛出 404。
这当然可能是由服务器端覆盖引起的。但是你可以在其他情况下扔一个410,所以这似乎排除了这一点。但是,如有疑问,您可以在.htaccess
中重置错误文档(除非您已经在使用自定义错误文档):
ErrorDocument 410 default
RewriteCond %{REQUEST_URI} ^/dir1/dir2/dir3/v_9991_0726dd5b5e8dd67a214c0c243436d131_all.css$ RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ - [R=410,L]
虽然这对规则的行为方式并没有真正的影响,但您不需要检查REQUEST_URI
的第一个RewriteCond
指令。您应该改为在RewriteRule
模式中执行此检查(这将更有效,因为这首先处理)。例如:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^dir1/dir2/dir3/v_9991_0726dd5b5e8dd67a214c0c243436d131_all.css$ - [NC,R=410]
NC
标志应该是多余的。
尽管如此,与现有指令的冲突是最可能的原因。删除所有其他指令。你仍然看到相同的行为吗?
您可以测试REQUEST_URI
服务器变量的值。您可以发出重定向并将REQUEST_URI
作为 URL 参数传递,也可以设置环境变量(但您需要注意每次重写的REDIRECT_<var>
)。
例如,在.htaccess
的顶部(或您尝试此操作的任何地方):
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^ /test.php?var=%{REQUEST_URI} [NE,R,L]
创建了一个虚拟test.php
文件,以避免对错误文档进行内部子请求。
我无法确定为什么服务器配置或站点代码强制 htaccess 中的"410 Gone"响应指令被 404 响应覆盖,因此不得不做这样的事情来告诉 googlebot 停止搜索定期清除的 CSS/JS 文件(并在重新生成时重命名)。
在 .htaccess 中:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule v_(.*)_(.*)$ /410response.php [L]
在 410响应中.php放置在根目录中:
<?php header($_SERVER['SERVER_PROTOCOL'].' 410 Gone');
更新一
尝试将 htaccess 用于 410 指令时的 404 响应是由服务器强制执行的,因为服务器显然具有自定义 410 文档,该文档显然路由到 404。 添加一个指令以防止然后正确允许使用 htaccess 在 RewriteRule 中返回模式匹配的 410。 (我以为我昨天已经检查过这是否有效,因为@MrWhite在上面的回答中说要控制服务器可能具有自定义 410;今天进行此检查时,它确实有效并指示服务器 410 到 404 重定向正在覆盖我的 410 指令。
ErrorDocument 410 default
RewriteRule test.txt$ - [NC,R=410]
怀特先生! 我在您在Stack Exchange上的一篇文章中找到了这个解决方案。