ChatGPT解决这个技术问题 Extra ChatGPT

注销:GET 还是 POST?

这个问题与一般何时使用 GET 或 POST 无关;它是关于处理退出 Web 应用程序的推荐方法。我已经找到了大量关于一般意义上的 GET 和 POST 之间差异的信息,但我没有找到这个特定场景的明确答案。

作为一个实用主义者,我倾向于使用 GET,因为实现它比 POST 简单得多;只需删除一个简单的链接,您就完成了。我能想到的绝大多数网站似乎都是这种情况,至少在我的脑海中是这样。甚至 Stack Overflow 也使用 GET 处理注销。

让我犹豫的是(虽然很老)的论点,即一些网络加速器/代理通过访问和检索他们在页面中找到的每个链接来预缓存页面,因此用户在点击它们时会得到更快的响应。我不确定这是否仍然适用,但如果是这种情况,那么理论上具有这些加速器之一的用户会在她登录后立即被踢出应用程序,因为她的加速器会找到并检索注销链接,即使她从未点击过。

到目前为止,我所阅读的所有内容都表明 POST 应该用于“破坏性操作”,而不会改变应用程序内部状态的操作(如查询等)应该使用 GET 处理。基于此,这里真正的问题是:

注销应用程序是否被视为破坏性操作/是否会改变应用程序的内部状态?

好吧,假设您是第一次访问该站点,并且不存在注销链接,那么您在登录时就会被注销。再次登录后就好了,因为注销 url 已经被缓存了。但是可以假设任何像样的加速器都能够过滤掉大多数注销 url。
HyperCas,过滤掉注销 URL 的加速器是我正在考虑的一个理论,也是我决定发布这个问题的原因之一。我有点不情愿只相信加速器逻辑,有一天有一个使用糟糕加速器的用户抱怨她无法登录。你知道他们是否遵循标准,或者是否存在这样的标准?
任何自动提交表单(例如)的加速器都将是恶意软件IMO......认为加速器会自动提交表单是完全不合逻辑的。想象一下你访问谷歌。它如何提交搜索表单?没有人可以解释恶意软件,因为它太不可预测并且不遵守规则。
@AlexW - 我想你误解了我的问题。我提出的加速器方案是在使用 GET 而不是 POST 时显示一个可能的问题,因此没有要发布的表单,只有简单的链接,加速器不会出现问题。
我意识到我已经为时已晚,但亚历克斯,这不是丹尼尔要问的。他的意思是,如果用户单击注销链接并且加速器返回缓存的注销页面而没有点击应用程序,那么用户将保持登录状态。与恶意软件无关,尽管 FYI 检查用户代理字符串不会修复无论如何。

D
David Murdoch

使用 POST

在 2010 年,使用 GET 可能是一个可以接受的答案。但是今天(2013 年),浏览器会预取他们“认为”你接下来会访问的页面。

这是 StackOverflow 开发人员之一在 twitter 上谈论这个问题:

我要感谢我的银行注销 GET 请求,感谢 Chrome 团队提供方便的 URL 预取。- Nick Craver (@Nick_Craver) 2013 年 1 月 29 日

有趣的事实:StackOverflow 曾经通过 GET 处理注销,但现在不再这样了。


感谢这次更新,戴夫。我什至没有注意到 SO 将他们的日志切换到 POST,老实说,我不知道 Chrome 内置了预取功能。最后,你引用的 twit 可能永远无法为我在我的问题中描述的问题提供更好的例子我的问题并证实了我的怀疑。我正在对您的答案进行投票并使其成为公认的答案。
在我的浏览器中,Stackoverflow 注销看起来像
  • 注销
  • 这是一个 GET,而不是一个 POST
    @Mark0978,点击链接。
    有趣的。这可能是我最不喜欢的功能之一,注销然后询问我是否确定。猜猜它可以防止预取让您注销,但亚马逊、Ebay 和 Gmail 都使用 GET 进行注销,而在用户被告知注销和实际注销事件之间没有那个技巧页面。我想在页面之间会导致很多人错误地认为他们已注销。 SO 上的问题很小,不涉及金钱,而且 99% 的一切都是公开的。
    @Red 根据 HTTP/1.1 标准,这是服务器的问题,而不是浏览器的问题。 GET 预计不会对服务器端产生副作用。该标准甚至说“用户没有要求副作用,因此不能对它们负责”。
    D
    Darrel Miller

    在 REST 中不应该有会话,因此没有什么可破坏的。 REST 客户端对每个请求进行身份验证。登录或退出,这只是一种错觉。

    您真正要问的是浏览器是否应该继续在每个请求上发送身份验证信息。

    可以说,如果您的应用程序确实产生了登录的错觉,那么您应该能够使用 javascript“注销”。无需往返。

    菲尔丁论文 - Section 5.1.3

    从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端


    我实际上并没有意识到这一点。然后我想我的应用程序根本不会很 RESTful,因为我使用 ASP.NET MVC 和 FormsAuthentication 并且它依赖于会话......
    但实际上登录信息保存在标有 httponly 属性的 cookie 中,以防止某些 xss 风险,这意味着它只能从服务器重置(手动清除 cookie 的不足)
    用户中的“手动”进入浏览器设置并选择“清除 cookie”选项。 “注销”网站几乎不是一种可接受的方式。
    @Remus Ahhh,杰出的网络浏览器如何让编写网络应用程序变得如此痛苦。
    @DarrelMiller 是的,但是不在服务器端撤销 JWT 是一个安全漏洞。即使令牌没有存储在服务器上,也应该在用户注销/更改密码/更改角色/退出/等时将它们列入黑名单,以防止滥用(至少在它们过期之前)。
    r
    raveren

    此处可能滥用 GET 的一种方式是,某人(可能是竞争对手:)在 Internet 上放置了带有 src="<your logout link>" ANYWHERE 的图像标签,如果您网站的用户偶然发现该页面,他将在不知不觉中退出。


    不,这是不对的。仅当发送正确的 cookie 数据时,注销链接才有效,它不会来自另一个域。即使会话 ID 存储在 url 中,这也不起作用,因为每个会话都会更改这些 ID。
    哇,我从来没想过!因此,还有另一个不使用 GET 的原因,以及我不明白为什么每个人都这样做的另一个原因。该死,现在我很想在我的帖子中包含一个stackoverflow.com/users/logout“图像”,看看会发生什么:-D
    src= 是一个简单的浏览器请求,它不是来自服务器端,而是来自客户端。它携带所有 cookie 并来自用户 IP。这就是广告跟踪像素起作用的原因。确定此类漏洞的唯一方法是检查引荐来源网址。
    SuperLogout.com 正是这样做的(在隐藏的图像中加载 /logout 个 URL),并且可以正常工作。
    re:SuperLogout ...我不知道为什么我点击了那个。
    m
    miorey

    您好,在我看来,当您登录时检查用户名/密码,如果它们匹配,您将创建登录令牌。

    CREAT 令牌 => 方法 POST

    当您注销时,您会破坏令牌,所以对我来说最合乎逻辑的方法应该是 DELETE

    DELETE 令牌 => 方法 DELETE


    有趣的角度。
    我在我的 Spring Boot REST 应用程序中使用该方法。
    是的,但 DELETE 的 URL 应该标识要删除的资源,因此它不能与 POST 中的相同。
    @RonInbar 同意,如果遵循 REST 100%,那么创建会话的 POST 应该转到 [主机名]/[用户名]/会话,如下文所述 VinayC。 DELETE 应该类似于 [host name]/[user name]/session/[session_id]。然而,使用 DELETE 处理会话资源的删除,即使从 cookie 而不是 URL 获取资源,也比使用另一个动词删除资源更好(同样,如果尝试遵循 REST 约定)。
    从概念上讲,只要 URL 不是 /logout,这就是有意义的,因为您不是删除注销(这没有任何意义),而是删除会话。所以我猜登录和注销都会到达同一个端点,只是用 POST 或 DELETE 来区分它们
    V
    VinayC

    正确地说,GET/POST(或其他动词)是对某些资源(由 URL 寻址)的操作 - 所以它通常与资源的状态有关,而不是与应用程序状态本身有关。因此,实际上,您应该有一个诸如 [host name]\[user name]\session 之类的 URL,然后“删除”将是注销操作的正确动词。

    以不是真正完整的 REST 方式 (IMO) 使用 [host name]\bla bla\logout 作为 URL,那么为什么要争论正确使用 GET/POST 呢?

    当然,我也在我的应用程序中使用 GET 来注销 url :-)


    在这种情况下,我会争辩说,在 URL 中包含 [user name] 部分似乎是不必要的,因为用户总是从他们自己的会话中注销(即删除);从来没有其他用户的:-)
    不是真的 - 我们说会话是一种资源,我们想删除它。因此,为了统一处理任何会话,您需要将用户名作为 URL 的一部分。您的论点就像在 [照片库]\图片上发出 PUT 操作意味着您正在添加到您的照片(可在 [照片库]\[用户名]\图片中获得)。必须明确处理不同的资源,其中不能有任何隐含性。该站点可能允许其他用户将图片添加到您的画廊 - 这将是访问控制的一部分,就像您可以拥有一个可以杀死任何人的会话的超级用户一样。
    从哲学上讲,您可以将会话和照片称为“资源”,但实际上我不会对它们一视同仁。会话本质上总是仅限于当前用户(因此称为会话),并且至少在 ASP.NET 中,无法访问其他用户的会话。甚至应用程序开发人员也无法直接枚举所有活动会话,也无法单独终止会话。您可以重新启动应用程序以终止所有会话(InProc),但我不会调用该访问控制。除了 URL,问题仍然存在:GET 还是 POST?
    资源,因此它的地址 (URL) 是 REST 的重要组成部分。因此,如果您像我所说的那样选择 URL,则 DELETE 将成为正确的词 - 而不是 GET 或 POST。此外,即使您将自己限制在 ASP.NET 中,您也始终可以使用自定义状态提供程序,它可以让您枚举会话并在需要时终止其他会话。对于开箱即用的进程内会话,global.asax 中的一些摆弄应该为您提供功能。这真的是一个是否需要这种功能的问题。对于不常见的需求,人们倾向于重新启动网站以将人们踢出网站。
    这对我来说最有意义。给 web api 一个会话路由并在其上调用 DELETE。是 ../session 或 ../session/current。谢谢@VinayC
    J
    Joel Etherton

    注销对应用程序本身没有任何作用。它改变了用户与应用程序相关的状态。在这种情况下,您的问题似乎更多地基于用户应如何启动命令以开始此操作。由于这不是“破坏性操作”,因此请确保会话被放弃或销毁,但您的应用程序或您的数据都没有被更改,因此允许这两种方法启动注销过程并非不可行。该帖子应由任何用户发起的操作(例如 - 用户单击“注销”)使用,而 get 可以保留用于应用程序发起的注销(例如 - 检测到潜在用户入侵的异常会通过注销 GET 强行重定向到登录页面)。


    这可能取决于应用程序(某种“级联删除”行为),但你是对的。
    @JoelEtherton 谢谢乔尔,我正在阅读答案,想知道什么时候能找到正确的答案。 :)
    这很令人困惑,因为注销会更改状态。 POST 是改变状态的动词。 GET 用于获取无状态数据。这很令人困惑,因为我们希望 POST 请求具有有效负载。如下所述,DELETE 在会话对象上最正确。
    @MichaelCole:我同意 POST 和 GET 之间的困难表示。不过,我不同意 DELETE 动词的用法。 DELETE 用于处理资源,会话不是这个意义上的资源。考虑一下,如果你可以删除它,那么你也应该能够把它。
    @JoelEtherton,是的,我同意 DELETE 和 PUT 会话有点奇怪:-)
    R
    Richard H

    预缓存的场景是一个有趣的场景。但我猜如果很多网站公司都不担心这一点,那么也许你也不应该担心。

    或者也许链接可以用javascript实现?

    编辑:据我了解,从技术上讲,GET 应该用于只读请求,不会更改应用程序状态。 POST 应该用于更改状态的写入/编辑请求。然而,对于一些状态变化的请求,其他应用程序问题可能更喜欢 GET 而不是 POST,我认为这没有任何问题。


    谢谢。数据库状态不会改变,但会话状态会改变。我看到的唯一问题是我在问题中提到的关于用户被踢出的问题。非破坏性但相当烦人。我通常也会遵循“如果大人物这样做,那一定没问题”的口头禅。我只是想知道其他人对此有何看法。
    R
    Rob

    好吧,如果您让您的 Web 应用程序通过注销脚本放弃会话,那么您通常也不需要。通常有一个会话变量对于您要放弃的会话是唯一的。


    您能否详细说明“注销脚本”?我不确定您是否指的是设置 cookie 过期时间(这并不能消除让用户手动注销的需要。)
    注销脚本将结束调用它的用户(实际上是浏览器)的会话。在 ASP.net 中,会话是可以放弃的服务器端对象。 PHP 也有类似的系统。因为该浏览器调用结束会话的脚本,它已经知道要结束哪一个,从而消除了对 POST 或 GET 变量的需要。
    是的,我现在明白了。我已经有了脚本,特别是 FormsAuthentication.SignOut(),但我的问题是关于如何调用脚本,如 GET 或 POST。
    哦,你有表格中的网址吗?如果您不向其传递任何信息,则无关紧要。可能发生的最糟糕的事情是有人手动打开脚本,将自己注销。如果没有必要,我什至不会将其设置为表单字段,脚本的链接也可以。如果您确实向脚本发送信息,我可能会进行 POST,以免向用户显示任何信息(除非他们查看页面源代码),如果他们刷新,他们会从浏览器收到警告(页面已过期),这可能是可取的。
    j
    jpluijmers

    我看不出注销(取消提升用户权限)是一种破坏性行为。那是因为“注销”操作应该只对已经登录的用户可用,否则它将被过时。

    您的浏览器 cookie 中包含的随机生成的字符串都代表您的用户会话。有很多方法可以销毁它,因此有效地注销只是为您的访问者提供的服务。


    wget 在蜘蛛模式下,在私有 Wiki 上使用正确的会话 cookie 是我实际上必须做的事情。当然,最早抓取的网址之一是 /logout
    尝试转至 SuperLogout.com,了解对 /logout 页面的 GET 请求的破坏性究竟有多大。例如,您必须再次登录 Gmail,再次登录聊天,在您滚动的任何环聊对话中找到自己的位置等 - 这仅适用于 Google.com。
    @DanDascalescu 您应该警告人们访问此页面将立即注销他们并且没有确认按钮!很生气的表情包