Rails:Rails 中的 POST 422(不可处理实体)?由于路线或控制器?
Posted
技术标签:
【中文标题】Rails:Rails 中的 POST 422(不可处理实体)?由于路线或控制器?【英文标题】:Rails: POST 422 (Unprocessable Entity) in Rails? Due to the routes or the controller? 【发布时间】:2015-01-21 18:37:07 【问题描述】:我试图在我的网站上为发布品牌名称的用户提供“积分”或“信用”。
我在适当的视图上有精美的 twitter 小部件...
<p><a href="https://twitter.com/share" class="twitter-share-button" data-text="Check Out This Awesome Website Yay" data-via="BrandName" data-hashtags="ProductName">Tweet</a>
<div id="credited"></div>
<script>window.twttr = (function (d, s, id)
var t, js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src= "https://platform.twitter.com/widgets.js";
fjs.parentNode.insertBefore(js, fjs);
return window.twttr || (t = _e: [], ready: function (f) t._e.push(f) );
(document, "script", "twitter-wjs"));
</script>
我把 JS 都写好了,而且很漂亮....
function creditTweet()
$.post(
"/credit_tweet",
,
function(result)
var text;
if (result.status === "noop")
text = "Thanks for sharing already!";
else if (result.status === "ok")
text = "5 Kredit Added";
$("#credited").html(text);
);
$(function()
twttr.ready(function (twttr)
window.twttr.events.bind('tweet', creditTweet);
);
);
现在问题出在控制器或路由中(我要发布的地方)。我认为路线很好,因为 POST 几乎可以正常工作,因为这是***上错误的描述 - “422 Unprocessable Entity (WebDAV; RFC 4918) 该请求格式正确,但由于语义错误而无法执行。”
那么,你们看到我在控制器中的 ruby 代码有什么问题吗?
class SocialKreditController < ApplicationController
TWEET_CREDIT_AMOUNT = 5
def credit_tweet
if !signed_in?
render json: status: :error
elsif current_user.tweet_credited
Rails.logger.info "Not crediting # current_user.id "
render json: status: :noop
else
Rails.logger.info "Crediting # current_user.id "
current_user.update_attributes tweet_credited: true
current_user.add_points TWEET_CREDIT_AMOUNT
render json: status: :ok
end
end
end
在我的 routes.rb 中,它非常简单,所以我怀疑这里有什么问题......
get 'social_kredit/credit_tweet'
post '/credit_tweet' => 'social_kredit#credit_tweet'
哪里哦,这个错误在哪里?我显然对 HTTP 请求一无所知。
【问题讨论】:
当 ActiveRecord 对象无法更新/保存时,IME rails 通常会返回 422。你的日志说什么? 看起来 .... 于 2014 年 11 月 24 日 00:34:53 -0500 开始 POST "/credit_tweet" for 127.0.0.1 由 SocialKreditController#credit_tweet 处理为 / 无法验证 CSRF 令牌真实性 Completed 422 Unprocessable Entity in 1ms ActionController::InvalidAuthenticityToken - ActionController::InvalidAuthenticityToken: 你能用显示这个错误的行从 Rails 服务器发布日志吗?另外,为什么你有两条路线get
和post
指向同一个方法?
【参考方案1】:
我搞定了!
我添加了一个...
skip_before_action :verify_authenticity_token
到控制器。
在查看日志并发现无法验证 CSRF 令牌时发现问题。
【讨论】:
您可能还想查看 this question 以获得不需要禁用 csrf 令牌检查的解决方案。 感谢@ihaztehcodez - 此skip_before_action :verify_authenticity_token 仅在用户登录后必需的控制器上使用。是否有任何主要原因我可能想要使用该链接中提供的AJax 解决方案在这个小sn-p上? @piratetone :是的,原因是安全性。 The rails security guide 很好地解释了 csrf。通常,您不应在没有充分理由的情况下禁用 csrf 检查(例如来自第三方 API 的回调)。在这种情况下,您完全有能力让 csrf 检查满意,这是最好的做法。 关闭安全是解决方案?【参考方案2】:ihaztehcodez(他最后一次活动是在 2016 年,所以它无助于推动他发布答案)提到 skip_before_action :verify_authenticity_token
技术并不那么安全,因为你失去了伪造保护。
他们提到最好/安全/'更好的实践',这里提到了解决方案WARNING: Can't verify CSRF token authenticity rails
例如
$.ajaxSetup(
headers:
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
);
或
$.ajax( url: 'YOUR URL HERE',
type: 'POST',
beforeSend: function(xhr) xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')),
data: 'someData=' + someData,
success: function(response)
$('#someDiv').html(response);
);
或
将其放入 ajax 请求中
headers:
'X-Transaction': 'POST Example',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
,
【讨论】:
【参考方案3】:我遇到了同样的问题。 加完就搞定了
skip_before_action :verify_authenticity_token
在您的 JS 调用或发送数据的控制器顶部。
class UserController < ApplicationController
skip_before_action :verify_authenticity_token
def create
end
end
如代码sn-p所示。
【讨论】:
【参考方案4】:我在开发 Rails 6 仅限 API 的应用程序时遇到了这个挑战。
我按照这里的答案 - Rails: How to implement protect_from_forgery in Rails API mode 在 Rails API 模式下实现protect_from_forgery,但是当我从邮递员:
Started POST "/api/v1/programs" for ::1 at 2021-02-23 18:42:49 +0100
Processing by Api::V1::ProgramsController#create as JSON
Parameters: "program"=>"name"=>"Undergraduate", "code"=>"UD", "affiliate_status"=>false, "motto"=>"Our motto is ...", "description"=>"This is a new program", "school_id"=>1
Can't verify CSRF token authenticity.
TRANSACTION (0.3ms) BEGIN
↳ app/controllers/api/v1/programs_controller.rb:27:in `create'
Baserecord::School Load (0.3ms) SELECT "schools".* FROM "schools" WHERE "schools"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
↳ app/controllers/api/v1/programs_controller.rb:27:in `create'
TRANSACTION (0.4ms) ROLLBACK
↳ app/controllers/api/v1/programs_controller.rb:27:in `create'
Completed 422 Unprocessable Entity in 30ms (Views: 0.8ms | ActiveRecord: 6.9ms | Allocations: 13172)
这是我解决的问题:
问题是由我的模型中的验证错误引起的。我为我正在调用的控制器添加到模型中的验证失败。在发出请求以查找错误后,我必须检查 Postman 返回的响应的正文:
"affiliate_status": [
"can't be blank"
]
一旦我按照这个答案修复了错误 - Rails: Validation fails for ActiveRecord in setting a random Boolean Attribute,之后一切正常。
就是这样。
我希望这会有所帮助
【讨论】:
【参考方案5】:如果您在带有 <%= csrf_meta_tags %>
的 HTML 标头中包含 Rails 元数据,它将生成以下内容。
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="ihwlaOLL232ipKmWYaqbSZacpJegQqooJ+Cj9fLF2e02NTQw7P/MfQyRuzruCax2xYWtEHWsb/uqiiZP6NWH+Q==" />
您可以从元数据中提取 CRSF 令牌并将其传递到您的异步请求中。
使用原生 js fetch
方法,您可以将其作为 x-csrf-token
标头传递。
这是一个用于增强标准 Rails 表单的 React 组件的修剪 onSave 处理程序。
onSaveHandler = (event) =>
const data = "Foo Bar";
const metaCsrf = document.querySelector("meta[name='csrf-token']");
const csrfToken = metaCsrf.getAttribute('content');
fetch(`/posts/$this.props.post_id`,
method: "PUT",
body: JSON.stringify(
content: data
),
headers:
'x-csrf-token': csrfToken,
'content-type': 'application/json',
'accept': 'application/json'
,
).then(res =>
console.log("Request complete! response:", res);
);
防伪是个好主意。这样我们就可以保持安全并且不会弄乱我们的 Rails 配置。
使用gem 'rails', '~> 5.0.5'
& "react": "^16.8.6",
【讨论】:
【参考方案6】:在 POST 请求中更新模型时可能会发生 422:
例如@user.update!(email: nil)
中的 users#update
将生成 422,如果在电子邮件上进行验证,例如 validates :email, presence: true
【讨论】:
以上是关于Rails:Rails 中的 POST 422(不可处理实体)?由于路线或控制器?的主要内容,如果未能解决你的问题,请参考以下文章
从 iOS 客户端返回状态 422 到 Rails 应用程序的 PATCH
Rails/Devise 登录在 Safari 上不起作用(422/CSRF 错误)
AWS Elastic Beanstalk 上的 Rails 应用程序返回 422 并显示“无法验证 csrf 令牌”