我在PHP中有一个小型路由引擎。我试图允许它可选地匹配不同的“格式”,例如对“/user/profile.json”或“/user/profile.xml”的请求。但是,它也应该只匹配一个简单的“/ user / profile”。
所以, if 如果格式存在,则必须是“.json”或“.xml”。但它根本不存在必需。
这是我到目前为止所做的:
#^GET /something/([a-zA-Z0-9\.\-_]+)(\.(html|json))?$#
显然,这不起作用。这允许请求任何“格式”,因为整个格式段是可选的。如何保持可选,但约束可以请求的格式?
答案 0 :(得分:4)
^GET /something/([a-zA-Z0-9._-]+)(\.(html|json))?$
允许第一个字符类中的点,因此任何文件扩展名都是合法的。我希望你是故意这样做的,因此可能有带点的文件名。
但是,这意味着如果文件名包含点,则必须以.html
或.json
结尾。正确?
所以将正则表达式更改为(使用\w
的{{1}}简写:
[A-Za-z0-9_]
答案 1 :(得分:2)
替代建议:
让客户端通过Accept Header in the HTTP Request(它所属的位置)指定所需的输出格式,而不是将所需的输出格式放入URL中。 Content negotiation已融入HTTP协议,因此您无需通过URL重新发送它。从技术上讲,将格式放入URL是错误的。您的URI应指向资源本身而不是资源表示。
另见W3C: Content Negotiation: why it is useful, and how to make it work
答案 2 :(得分:0)
您遇到的问题是因为大多数扩展程序都是字母数字,但在您的正则表达式中,您允许使用点和字符:
#^GET /something/[a-zA-Z0-9\.\-_]+(\.(html|json))?$#
问题部分为[a-zA-Z0-9\.\-_]+
。对于.csv的例子来说,因为它仍然匹配该字符范围。
如果文件名中有点,则默认情况下,它有文件扩展名(有意或无意)。文件My.Finance.Documents
的扩展名为“.Documents”,即使您将其视为文本文件或其他内容。
我讨厌这样做,但我想你可能想在你的正则表达式中有一个更大的条件,这是一个例子,我没有测试过它:
#^GET /something/([^\.]+|.*\.(?:html|json))$#
基本上,如果文件名中没有点,那就没关系。如果它确实有一个点(这保证它有一个扩展名),它必须以.html或.json结尾。