如何在使用Trac和WSGI时,在Genshi模板中获取远程用户代理?
我正在尝试对一个Trac项目管理网站进行一些定制,但遇到了一个有趣的问题。这个项目有一组图片,包括SVG和PNG格式。SVG图片有很多优点,比如可以包含多个链接,而且传输的文件大小比PNG小,而PNG则比较大,只能链接到一个文档。
我意识到可以用jQuery在页面加载后检测用户的浏览器类型,然后把PNG图片替换成SVG版本,但这样做会导致PNG图片还是会发送给所有用户。我也可以让Genshi把PNG替换成SVG,然后再用jQuery把PNG放回去,但结果还是一样。我可以用jQuery为所有用户插入合适的图片,但这样就显得很傻,因为本来应该由服务器来处理的事情却要客户端来做。
有没有办法在Genshi模板中获取浏览器信息?这比直接调用环境变量要复杂一些,因为我是在用WSGI运行Trac。我查看了repr(locals())
的输出,但没有看到任何能解决我问题的东西。我也想避免修改Trac的源代码。
2 个回答
user_agent = environ.get('HTTP_USER_AGENT', None)
或者如果 environ
被某种 Request
对象包裹起来的话:
user_agent = request.user_agent
顺便说一下,你可能应该查看一下 HTTP_ACCEPT
这个头信息,而不是 HTTP_USER_AGENT
,这样可以更好地了解应该发送什么样的内容。
好的,我对这个问题做了一些研究,不是通过查找源代码,而是写了一个自定义的 Genshi 处理器,它可以输出本地所有元素的递归 repr()
(这得益于一个之前的问题,它讲解了如何打印出所有作用域内的变量)。我最开始没有注意到 req
对象。其实只需要用 req.environ['HTTP_USER_AGENT']
就能搞定。问题在于一开始找不到 req
对象。我查找源代码时仍然找不到模板是在哪里实例化的,所以这样的方法比修补程序要简单得多,也更有效。
为了完整起见,这里是我用来替换 Gecko 浏览器新版本的 logo 的 Genshi 模板代码。这个方法有点小技巧,可能不是最优的,但它有效,并且不会把 SVG 发送给那些谎称自己是“像 Gecko”的浏览器,但实际上无法正确渲染 SVG——是的,我在说你,Webkit。
<py:if test="'Gecko/' in req.environ['HTTP_USER_AGENT'] and [int(x.split('/')[1]) for x in req.environ['HTTP_USER_AGENT'].split() if x.startswith('Gecko')][0] > 20080101">
<div py:match="div[@id='header']">
<object type="image/svg+xml" id="svgLogo" data="${href.chrome('site/logo.svg')}" style="width=${chrome['logo']['width']}px; height=${chrome['logo']['height']}px;"></object>
</div>
</py:if>