检测浏览器是否支持WebP格式?(服务器端)

32

已经有一个关于使用客户端检测WebP支持的主题讨论了(链接)。如何使用服务器端检测WebP支持?


这意味着第一次加载页面时会加载 .jpg,这有点违背了初衷。 - Gajus
你可以从 $_SERVER['HTTP_ACCEPT'] 中获取它吗? - putvande
请查看此帖子:https://dev59.com/lm_Xa4cB1Zd3GeqPxRs-#17664287 - Cícero Verneck Corrêa
4个回答

83
今天,您应该检查 accept 标头是否包含 image/webp。所有支持 WebP 的浏览器都会在其所有请求(包括图像和非图像)的接受字符串中发送此标头。简而言之:
if( strpos( $_SERVER['HTTP_ACCEPT'], 'image/webp' ) !== false ) {
    // webp is supported!
}

你可能想使用preg_match并添加单词边界检查和大小写不敏感性,但在现实世界中这应该是可以的。


以下是我几年前的原始答案,当时上述方法不可靠

"正确"的方法是检查发送的accept头文件,但Chrome中的一个错误意味着它不会列出image/webp,即使它支持它。

这是一个相关的论坛帖子:https://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/6nYUpcSAORs

其中链接到此bugtracker:https://code.google.com/p/chromium/issues/detail?id=169182,它又链接到这个bugtracker:https://code.google.com/p/chromium/issues/detail?id=267212

最终结果?虽然还没有实现,但很快Google Chrome将明确列出image/webp作为接受类型,用于图像和非图像请求。因此,您的用于提供HTML的脚本可以检查它。Opera已经将image/webp作为其标准accept头文件的一部分发送(无论是否是图像请求)。

所以,你可以这样检查:

if( strpos( $_SERVER['HTTP_ACCEPT'], 'image/webp' ) !== false || strpos( $_SERVER['HTTP_USER_AGENT'], ' Chrome/' ) !== false ) {
    // webp is supported!
}

(你可能想使用 preg_match 代替,并添加单词边界检查和不区分大小写,但在现实世界中这应该是可以的。您可能还想检查至少 Chrome 的版本 6,但几乎没有人使用过时版本,所以没有太多意义)


有人知道Chrome是否已经支持这个了吗?原始答案是去年8月份的。 - Maelish
@Maelish 第一个漏洞跟踪器上的线程以“我现在也看到http请求的image/webp头了”结束(日期为2月),所以我猜应该是可以的。最简单的检查方式就是尝试一下! - Dave
2
火狐浏览器自版本65起支持WebP图像,但自版本66起,他们决定将image/webp从接受头中移除到主文档中。 - Māris Kiseļovs
1
似乎Firefox再次在Accept中发送image/webp。 - Alexander Shostak
3
注意!运行Big Sur的Mac上的Safari当前不会在接受头中发送image/webp。这是我现在在Safari中看到的接受头的样子: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 - Andreas Heintze
显示剩余3条评论

2

Dave的回答很好,但不适用于所有浏览器。我使用以下方法:

function GetBrowserAgentName($user_agent) {
    if (strpos($user_agent, 'Opera') || strpos($user_agent, 'OPR/')) return 'Opera';
    elseif (strpos($user_agent, 'Edge')) return 'Edge';
    elseif (strpos($user_agent, 'Chrome')) return 'Chrome';
    elseif (strpos($user_agent, 'Safari')) return 'Safari';
    elseif (strpos($user_agent, 'Firefox')) return 'Firefox';
    elseif (strpos($user_agent, 'MSIE') || strpos($user_agent, 'Trident/7')) return 'Internet Explorer';
    return 'Other';
}

所以在检查浏览器之后:

  $BrowserAgentName = GetBrowserAgentName($_SERVER['HTTP_USER_AGENT']);
  If ($BrowserAgentName == 'Chrome' || $BrowserAgentName =='Opera') {
  // webp is supported!

  }

这里我只添加了Opera和Chrome,您可以使用更深层次的检测器来检测浏览器版本,并在if{}中添加更多的代理。但是,当浏览器更新以支持image/webp时,您需要更新此代码。


9
应该避免通过检查浏览器来检查功能;这会导致代码很容易出现问题,必须手动进行维护(也是当前浏览器发送的用户代理标头极其复杂和自相矛盾的主要原因)。这就是为什么我建议直接通过在接受标头中查找“image/webp”来检查特性。支持webp的所有浏览器都会列出此内容。进行浏览器检查的唯一原因是暂时解决特定已知(最好是已报告的)错误,如我的原始回答所述。 - Dave

1
我发现 Facebook 存在一个小问题 - 他们的 facebookexternalhit 机器人(当有人在帖子中发布地址时,它会爬取你的网站)还不能识别 webp 图片。因此,我已经添加了以下检查来禁用客户网站上的 webp 图片,以供 Facebook 的机器人使用:
if (strstr(strtolower($_SERVER["HTTP_USER_AGENT"]), "facebook"))
    return false;

否则,当网页被分享时,它将显示错误的图片(它在页面中找到的第一个JPG)。

1
在我的情况下,我使用的是C# Asp.Net MVC。该SO没有指定技术,因此我发现自己正在查看此线程。对于任何其他碰巧遇到类似问题的人,这是我想出的解决方案:
bool acceptsWebP = Request.AcceptTypes.Contains("image/webp");
string ext = Path.GetExtension(image.ImagePath);
string webP = image.ImagePath.Replace(ext, ".webp");
if (acceptsWebP)
{
    <img class="img-fluid lazy" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-src="\Uploads\@webP" alt="@item.ProductName">
}
else
{
    <img class="img-fluid lazy" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" data-src="\Uploads\@image.ImagePath" alt="@item.ProductName">
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接