如何检测 GET 请求是否来自浏览器

How to detect if a GET request is from a browser or not

我正在寻找一种方法来向用户显示 html,如果他们从浏览器调用,或者只是在 JSON 中给他们 API 响应,如果调用从应用程序、带有 curl 的终端或一般任何其他方式。

我知道很多 API 这样做,我相信 Django 的 REST 框架可以做到这一点。

我已经能够通过将浏览器的用户代理传递给 curl 来欺骗其中的一些 API,所以我知道这是使用用户代理完成的,但我该如何实现呢?涵盖所有可能的或大多数用户代理。

必须有 file/database 或正则表达式,这样我就不必担心每隔几个月更新一次用户代理列表,也不必担心使用最新浏览器的用户可能无法使用访问我的网站。

使用@reevkandari 的 pastebin,以下 Python 代码在我的生产环境中运行良好

browser_useragents = ["ABrowse", "Acoo Browser", "America Online Browser", "AmigaVoyager", "AOL", "Arora", "Avant Browser", "Beonex", "BonEcho", "Browzar", "Camino", "Charon", "Cheshire", "Chimera", "Chrome", "ChromePlus", "Classilla", "CometBird", "Comodo_Dragon", "Conkeror", "Crazy Browser", "Cyberdog", "Deepnet Explorer", "DeskBrowse", "Dillo", "Dooble", "Edge", "Element Browser", "Elinks", "Enigma Browser", "EnigmaFox", "Epiphany", "Escape", "Firebird", "Firefox", "Fireweb Navigator", "Flock", "Fluid", "Galaxy", "Galeon", "GranParadiso", "GreenBrowser", "Hana", "HotJava", "IBM WebExplorer", "IBrowse", "iCab", "Iceape", "IceCat", "Iceweasel", "iNet Browser", "Internet Explorer", "iRider", "Iron", "K-Meleon", "K-Ninja", "Kapiko", "Kazehakase", "Kindle Browser", "KKman", "KMLite", "Konqueror", "LeechCraft", "Links", "Lobo", "lolifox", "Lorentz", "Lunascape", "Lynx", "Madfox", "Maxthon", "Midori", "Minefield", "Mozilla", "myibrow", "MyIE2", "Namoroka", "Navscape", "NCSA_Mosaic", "NetNewsWire", "NetPositive", "Netscape", "NetSurf", "OmniWeb", "Opera", "Orca", "Oregano", "osb-browser", "Palemoon", "Phoenix", "Pogo", "Prism", "QtWeb Internet Browser", "Rekonq", "retawq", "RockMelt", "Safari", "SeaMonkey", "Shiira", "Shiretoko", "Sleipnir", "SlimBrowser", "Stainless", "Sundance", "Sunrise", "surf", "Sylera", "Tencent Traveler", "TenFourFox", "theWorld Browser", "uzbl", "Vimprobable", "Vonkeror", "w3m", "WeltweitimnetzBrowser", "WorldWideWeb", "Wyzo", "Android Webkit Browser", "BlackBerry", "Blazer", "Bolt", "Browser for S60", "Doris", "Dorothy", "Fennec", "Go Browser", "IE Mobile", "Iris", "Maemo Browser", "MIB", "Minimo", "NetFront", "Opera Mini", "Opera Mobile", "SEMC-Browser", "Skyfire", "TeaShark", "Teleca-Obigo", "uZard Web", "Thunderbird", "AbiLogicBot", "Link Valet", "Link Validity Check", "LinkExaminer", "LinksManager.com_bot", "Mojoo Robot", "Notifixious", "online link validator", "Ploetz + Zeller", "Reciprocal Link System PRO", "REL Link Checker Lite", "SiteBar", "Vivante Link Checker", "W3C-checklink", "Xenu Link Sleuth", "EmailSiphon", "CSE HTML Validator", "CSSCheck", "Cynthia", "HTMLParser", "P3P Validator", "W3C_CSS_Validator_JFouffa", "W3C_Validator", "WDG_Validator", "Awasu", "Bloglines", "everyfeed-spider", "FeedFetcher-Google", "GreatNews", "Gregarius", "MagpieRSS", "NFReader", "UniversalFeedParser", "!Susie", "Amaya", "Cocoal.icio.us", "DomainsDB.net MetaCrawler", "gPodder", "GSiteCrawler", "iTunes", "lftp", "MetaURI", "MT-NewsWatcher", "Nitro PDF", "Snoopy", "URD-MAGPIE", "WebCapture", "Windows-Media-Player"]
    if any(browser_useragent in request['userAgent'] for browser_useragent in browser_useragents):
        return "<html>Website HTML</html>"
else:
    return api JSON or XML

我知道这个 post 已经有几年了,但是自从我偶然发现它之后...

tldr; 除非绝对必要,否则不要使用用户代理来确定 return 格式。使用 Accept header 或(不太理想)使用单独的 endpoint/URL.

为特定端点设置所需 return 格式的标准和最 future-proof 方法是使用 Accept header。 Accept 明确设计为允许客户端声明他们想要 return 的响应格式。该值将是标准 MIME 类型。

默认情况下,Web 浏览器将发送 text/html 作为 Accept header 的值。大多数 Javascript 库和前端框架将发送 application/json,但如果需要,通常可以将其显式设置为其他内容(例如 text/xml)。我知道的所有移动应用程序框架和 HTTP 客户端库都可以根据需要设置此 header。

尝试使用用户代理来简单地确定响应格式有两个大问题:

  1. 该列表将是巨大的。您将需要考虑今天需要支持的每个可能的客户端。如果这个端点在内部使用,这可能不是一个直接的问题,因为你 可能 能够强制你接受哪些用户代理(可能导致它在未来会出现一系列问题,例如,强制您的用户无限期地使用特定版本的 Internet Explorer)这将有助于使此列表变小。如果要向外部公开此端点,您几乎肯定会错过一些您急需接受的东西。
  2. 该列表将更改。您需要说明明天、下周、明年和五年后需要支持的每个可能的客户。这成为 self-induced 维护难题。

关于 Accept 的两个注释:

  1. 请先阅读如何使用 Accept header,然后再尝试针对它实施。这是来自该网站的实际示例:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9。鉴于此,我会 return 返回 HTML。
  2. header 的值可以是 */*,基本上只是表示“随便”或“我不在乎”。那时,允许服务器确定响应格式。