从 iOS 客户端返回状态 422 到 Rails 应用程序的 PATCH
Posted
技术标签:
【中文标题】从 iOS 客户端返回状态 422 到 Rails 应用程序的 PATCH【英文标题】:PATCH to Rails app from iOS Client Returning Status 422 【发布时间】:2014-01-23 08:44:06 【问题描述】:我有一个带有 Business
模型对象的 Rails 应用程序,其计数为 visits
。我有一个使用 AFNetworking 2.0 与这个 Rails 应用程序交互的 ios 客户端,当用户在应用程序中点击一个业务时,它会向 Rails 应用程序发送一个 PATCH,为该业务增加 visits
。但是,我从服务器收到状态代码 422“无法处理的实体”错误,并且服务器上企业的 visits
计数没有增加。
AFHTTPSessionManager - iOS
- (NSURLSessionDataTask *)visitVenue:(NOTVenue *)venue withCompletionBlock:(void (^)(BOOL success))completionBlock
NSURLSessionDataTask *dataTask = [self PATCH:[NSString stringWithFormat:@"businesses/%li.json", (long)[venue.identifier integerValue]]
parameters:@@"visits": @(venue.numberOfVisits + 1)
success:^(NSURLSessionDataTask *task, id responseObject)
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
if (httpResponse.statusCode == 200)
dispatch_async(dispatch_get_main_queue(), ^
completionBlock(YES);
);
else
dispatch_async(dispatch_get_main_queue(), ^
completionBlock(NO);
);
failure:^(NSURLSessionDataTask *task, NSError *error)
dispatch_async(dispatch_get_main_queue(), ^
completionBlock(NO);
);
];
return dataTask;
业务控制器 - Rails
# PATCH/PUT /businesses/1
# PATCH/PUT /businesses/1.json
def update
respond_to do |format|
if @business.update(business_params)
format.html redirect_to @business, notice: 'Business was successfully updated.'
format.json head :no_content
else
format.html render action: 'edit'
format.json render json: @business.errors, status: :unprocessable_entity
end
end
end
【问题讨论】:
【参考方案1】:如果 Web API 允许增加模型对象的计数器,它应该有一个专用的“方法”。
一般来说,如果客户端本身递增在它之前从服务器接收到的 本地副本 上执行的计数器然后尝试,递增计数器 功能将无法可靠地工作通过编写 PATCH 请求来更新服务器的值,其中客户端仅发送值 local_counter+1
。同时,其他客户端可能有相同的想法,在这种情况下,服务器上的计数器值将损坏。此外,可以将服务器上的计数器更新为 any 值 - 这当然是不希望的。
这会导致计数器变量对于客户端必须只读。
客户端必须有其他方式(由 Web API 定义)来完成此操作。例如,REST API 将定义客户端可以创建的特定“资源”(例如某种“票证”或“预订”)。此资源的创建将具有递增服务器上的计数器变量的效果。
编辑
如果您正在测试 Web API,那么命令行工具 curl
是无价的:
测试 PATCH 请求:
在 Terminal.app 中输入以下命令:
curl -sSv -X PATCH \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '"email”:”jappleseed@mail.com"' \
http://localhost:3000/api/v1/users/123 \
| python -m json.tool
【讨论】:
谢谢,这绝对有帮助;我对客户端服务器设计很陌生。虽然我肯定会改变我的方法,但你能解释一下为什么 PATCH 会返回 422 吗?为什么它不起作用仍然没有意义。 @sethfri 我不知道它为什么会发送 422。如果 Web 服务是由您实现的,您应该知道原因;) 422(不可处理实体)不是 HTTP 1.1 状态码,而是它由 WebDAV (RFC 4918) 定义。我怀疑 Rails 核心会发出该代码。 它就在 Rails 生成的控制器代码中 - :unprocessable_entity。我只是想不通为什么要发送。我的 PATCH 参数看起来是正确的,对吧(如果在这种情况下 PATCH 是正确的方法)? @sethfri:unprocessable_entity
确实映射到状态码 422。也就是说,您的 update
方法失败,原因不明(对我来说)。您可以检查数据模型。
CouchDeveloper: 422 是一个HTTP/1.1状态码;它只是没有在 RFC 2616 中定义。【参考方案2】:
在Rails API site 上找到了正确的解决方案。代码如下:
class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_action :verify_authenticity_token, if: :json_request?
protected
def json_request?
request.format.json?
end
end
【讨论】:
以上是关于从 iOS 客户端返回状态 422 到 Rails 应用程序的 PATCH的主要内容,如果未能解决你的问题,请参考以下文章
Rails API 422 无法处理的实体:没有可用的验证密钥,heroku
如何反序列化 422 无法处理的实体错误模型并将错误绑定到 asp.net core razor pages 模型状态
Rails:Rails 中的 POST 422(不可处理实体)?由于路线或控制器?
Angular + Rails:POST 请求 422/CSRF 错误