【问题标题】:What could cause an app in production to vary from development in such a way that all http requests become GET requests?什么可能导致生产中的应用程序与开发中的应用程序不同,以至于所有 http 请求都变成 GET 请求?
【发布时间】:2016-03-04 13:41:54
【问题描述】:

我有一个应用程序在我的本地机器上的开发中运行良好,但是当我在 Heroku 上部署它时出现了一些意外行为。

首先,注销链接停止工作。在开发中,注销链接通过发送 DELETE 请求来工作,该请求被路由到 session#destroy。当您在生产环境中单击链接时,它会将您带到 example.herokuapp.com/logout(由于页面不存在而引发错误),而不是激活 #destroy 操作。

其次,任何其他破坏链接开始表现得像显示链接。和上面的注销链接很相似,只是它显示了要删除的记录,并没有删除。

第三,我有几个自定义操作 #claim 和 #release 都设置为使用 POST http 请求来激活操作。 (这些操作分别将当前用户设置为记录的所有者,或者将记录的所有者设置为 nil)这些都在开发中运行良好,但在生产中却不行。与上面的注销问题类似,在生产环境中单击声明链接会尝试将用户带到 example.herokuapp.com/claim.1(另一个不存在的页面),而不是通过 records#claim 操作声明记录 1。

我做了一些挖掘,发现所有这些问题的根源是在生产中,每个请求都被作为 GET 请求处理。我可以通过切换到 GET 而不是 DELETE 或 POST 来使注销、声明和释放操作起作用,但这是一个肮脏的解决方案,它不会修复 records#destroy 操作。我想 Heroku 可能不喜欢我使用的链接语法,所以我尝试从这里更改链接的语法:

<%= link_to 'Destroy', booking, method: :delete, data: { confirm: 'Are you sure?' } %>

到那个:

<%= link_to 'Destroy', delete_booking_path(booking) data: { confirm: 'Are you sure?' } %>

这些链接既可用于开发,也可用于生产。

开发和生产都使用 Rails 4.2.4 和 ruby​​ 2.2.2p95。当我第一次将项目部署到 Heroku 时使用的是 Ruby 版本 2.0.0,但在这些问题开始后我升级以尝试最小化开发和生产之间的差异。我在开发中使用 SQLite3,而 Heroku 在生产中使用 Postgres。

总的来说,我对开发还很陌生,跟踪开发和生产之间差异的问题对我来说尤其新鲜。我还应该看什么来解决这个问题?你知道任何可能产生这些结果的现象吗?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 heroku


    【解决方案1】:

    为了让link_todelete 方法一起工作,Rails 需要unobtrusive scripting adapter for jQuery

    • 确保您的 Gemfile 具有

      gem 'jquery-rails'

    • 确保 app/assets/javascripts/application.js

      //= require jquery
      //= require jquery_ujs

    • 确保您的 app/views/layouts/application.html.erb 具有

      &lt;%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' =&gt; true %&gt;
      &lt;%= javascript_include_tag 'application', 'data-turbolinks-track' =&gt; true %&gt;

      head 标签内。如果您不打算使用 Turbolinks,请删除 'data-turbolinks-track' =&gt; true 部分。

    PS:不要忘记检查控制台是否有生产中的 JS 错误。与开发相比,资产在生产中的服务通常不同。它们被缩小、连接、缓存等。

    【讨论】:

    • 非常感谢您的回答!我今天要检查所有这三个,我会让你知道我发现了什么。出于好奇,缺少其中一个会如何影响 Heroku 上的生产,但不会影响我机器上的开发? localhost 是否能够更好地处理由此产生的故障?再次感谢!
    • Gemfile 有 gem 'jquery-rails' ;查看。 application.js 有 //= require jquery//= require jquery_ujs ;检查 application.html.erb 有两个特定的行;也检查一下。
    • 再次感谢您的帮助,我已经准备好所有这些部件,但取出 Turbolinks 部分并没有帮助。但还是非常感谢你。我希望这将有助于其他人解决类似问题。
    • 你检查过JS控制台吗?
    • 我查看了dashboard.heroku.com/apps/example-app-name/logs 的日志,并没有看到任何 JS 错误。有更好的地方看吗?
    【解决方案2】:

    扩展 Mihai-Andrei Dinculescu 的回答。

    您当然应该勤奋,不要将损坏的代码投入生产,但在某些情况下,您可能希望强化应用的某些方面,以便即使 javascript 失败,它们也能正常工作。

    首先要了解一下 Rails 如何实现扩展的 HTTP 动词集的一些基本知识。

    浏览器通常仅原生支持 POST 和 GET 请求。要伪造其他动词,例如 DELETE, PUT, PATCH,Rails 依赖于 Rack::MethodOverride 中间件。

    MethodOverride 在 POST 请求发送到服务器时启动。它在请求正文中查找 _method 键并更改请求方法标头。因此,当 Rails 收到请求时,它似乎一直是一个 DELETE 请求。

    link_to 使用jquery_ujs 来伪造扩展的动词集。 jquery_ujsonClick 事件处理程序委托给具有 data-method 属性的链接,此处理程序会阻止默认操作(发送 GET 请求)并在 javascript 中创建表单并提交 POST 请求。

    但是当 javascript 失败时,您只有一个普通的旧锚元素,而 HTML 中的锚只发送 GET 请求。

    但它的兄弟 button_to 实际上创建了一个包含单个按钮(以及一些隐藏输入)的表单,因此即使客户端关闭了 javascript 或存在网络故障(比您想象的更常见)它也可以工作.

    <%= button_to 'Sign out', session_path, method: :destroy %>
    

    【讨论】:

    • 感谢您的回答!您的回答有助于巩固我不久前得到的一些没有意义且没有坚持的建议。有人告诉我,对于不是获取请求的任何内容,通常最好使用button_to。但是他们没有很好地解释为什么,所以在阅读您的答案之前我基本上都忘记了,并且它与那个只记得一半的建议非常吻合。我非常感谢您帮助我理解概念和内部工作原理。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2016-04-19
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2020-10-23
    • 1970-01-01
    相关资源
    最近更新 更多