草庐IT

ios - Obj-C - POST JSON 数据到服务器?

coder 2023-07-29 原文

对不起,这个新问题,但我正在为这个问题撕心裂肺。我可以通过 FireFox 的 POSTER 之类的程序成功地将数据发布到我的端点 URL。但是,我正在尝试将相同的 JSON 数据从我的应用程序发布到我的端点 URL(Drupal 服务 push_notifications 端点),但由于某种原因它无法成功发布。这是我正在使用的代码:

ViewController.m

NSString *urlString1 = @"http://app.com/endpoint001/push_notifications";
 NSDictionary *jsonBodyDict = @{@"token":postDeviceID, @"type":@"ios"};
 NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:nil];
 // watch out: error is nil here, but you never do that in production code. Do proper checks!

 NSString *urlString2 = [NSString stringWithFormat:@"http://app.com/endpoint001/push_notifications?token=%@&type=%@",
                         postDeviceID,@"ios"];

 NSMutableURLRequest *request = [NSMutableURLRequest new];
 request.HTTPMethod = @"POST";

 // for alternative 1:
 [request setURL:[NSURL URLWithString:urlString1]];
 [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
 [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
 [request setHTTPBody:jsonBodyData];
 [request addValue:csrfToken forHTTPHeaderField:@"X-CSRF-Token"];

 // for alternative 2:
 [request setURL:[NSURL URLWithString:urlString2]];
 // no body needed, though that ultimately depends on your server. Also, I didn't test this for lack of a backend :)

 NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
 NSURLSession *session = [NSURLSession sessionWithConfiguration:config
                                                       delegate:nil
                                                  delegateQueue:[NSOperationQueue mainQueue]];
 NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                         completionHandler:^(NSData * _Nullable data,
                                                             NSURLResponse * _Nullable response,
                                                             NSError * _Nullable error) {
                                             NSLog(@"Yay, done! Check for errors in response!");

                                             NSHTTPURLResponse *asHTTPResponse = (NSHTTPURLResponse *) response;
                                             NSLog(@"The response is: %@", asHTTPResponse);
                                             // set a breakpoint on the last NSLog and investigate the response in the debugger

                                             // if you get data, you can inspect that, too. If it's JSON, do one of these:
                                             NSDictionary *forJSONObject = [NSJSONSerialization JSONObjectWithData:data
                                                                                                           options:kNilOptions
                                                                                                             error:nil];
                                             // or
                                             NSArray *forJSONArray = [NSJSONSerialization JSONObjectWithData:data
                                                                                                     options:kNilOptions
                                                                                                       error:nil];

                                             NSLog(@"One of these might exist - object: %@ \n array: %@", forJSONObject, forJSONArray);

                                         }];
 [task resume];

注:我在用户成功登录后放入了这段代码,所以我不确定是否需要启动一个全新的连接?如果 session 和 CSRF token 已存在,如何将我的数据发布到服务器?我的代码应该是什么样的?回答这个问题的人会出现在我的圣诞名单上...... O_O

NSLog 响应:
2017-07-17 17:31:11.421281-0700 app[977:206852] Yay, done! Check for errors in response!
2017-07-17 17:31:11.422198-0700 app[977:206852] The response is: <NSHTTPURLResponse: 0x170239b40> { URL: http://app.com/endpoint001/push_notifications?token=9526687d594944513b0wabf704eae3223f0de9bf69136a0aae3ab046863474b1&type=ios } { status code: 401, headers {
    "Cache-Control" = "no-cache, must-revalidate";
    Connection = "keep-alive";
    "Content-Type" = "application/json";
    Date = "Tue, 18 Jul 2017 00:14:35 GMT";
    Expires = "Sun, 19 Nov 1978 05:00:00 GMT";
    Server = Apache;
    "Transfer-Encoding" = Identity;
    Vary = Accept;
    "X-Content-Type-Options" = nosniff;
} }
2017-07-17 17:31:27.172085-0700 app[977:207024] XPC connection interrupted
2017-07-17 17:31:27.172311-0700 app[977:206852] One of these might exist - object: (
    "CSRF validation failed"
) 
 array: (
    "CSRF validation failed"
)

最佳答案

汤姆的回答给出了正确的方向,但我看到缺乏描述代码实际所做的事情让你感到困惑。此外,您使用的是不推荐使用的方法(来自 NSURLConnection ),所以我使用 NSURLSession 做了一个快速(未经测试)的示例及其相关类。别担心,它基本上是一样的。

话虽如此,您在原始代码中尝试此操作的方式让我怀疑您是否真的在发送 json 正文(即您的后端期望),或者更确切地说系统依赖于无聊的 URL 参数。所以我在我的代码中添加了两种方式:

NSString *postDeviceID = @"something";

NSString *urlString1 = @"http://myurl.com/endpoint01/push_notifications";
NSDictionary *jsonBodyDict = @{@"token":postDeviceID, @"type":@"ios"};
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:nil];
// watch out: error is nil here, but you never do that in production code. Do proper checks!

NSString *urlString2 = [NSString stringWithFormat:@"http://myurl.com/endpoint01/push_notifications?token=%@&type=%@",
                        postDeviceID,@"ios"];

NSMutableURLRequest *request = [NSMutableURLRequest new];
request.HTTPMethod = @"POST";

// for alternative 1:
[request setURL:[NSURL URLWithString:urlString1]];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPBody:jsonBodyData];

// for alternative 2:
[request setURL:[NSURL URLWithString:urlString2]];
// no body needed, though that ultimately depends on your server. Also, I didn't test this for lack of a backend :)

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config
                                                      delegate:nil
                                                 delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                        completionHandler:^(NSData * _Nullable data,
                                                            NSURLResponse * _Nullable response,
                                                            NSError * _Nullable error) {
                                            NSLog(@"Yay, done! Check for errors in response!");

                                            NSHTTPURLResponse *asHTTPResponse = (NSHTTPURLResponse *) response;
                                            NSLog(@"The response is: %@", asHTTPResponse);
                                            // set a breakpoint on the last NSLog and investigate the response in the debugger

                                            // if you get data, you can inspect that, too. If it's JSON, do one of these:
                                            NSDictionary *forJSONObject = [NSJSONSerialization JSONObjectWithData:data
                                                                                                          options:kNilOptions
                                                                                                            error:nil];
                                            // or
                                            NSArray *forJSONArray = [NSJSONSerialization JSONObjectWithData:data
                                                                                                    options:kNilOptions
                                                                                                      error:nil];

                                            NSLog(@"One of these might exist - object: %@ \n array: %@", forJSONObject, forJSONArray);

                                        }];
[task resume];

您的后端也可能支持这两种方式,但学习如何构建合适的 json 主体总是有帮助的。
请注意,tom 的代码让您认为它已发布的原因是您似乎误解了 NSURLConnection有效(除非您排除了您依赖的代码):对象始终按照您使用它的方式构建,因此 if (conn)总是在 YES分支。这并不意味着连接,即实际加载成功。初始值设定项返回 nil如果它不能创建一个实例,而不是一个有效的实例仅仅依赖于连接到它的目标时被拒绝的数据。您不会以这种方式收到错误消息(您需要为此依赖委托(delegate))。

我展示的 session 方法为您提供了一个完成块,您可以在其中调查服务器响应的内容,以进一步追踪出了什么问题。您可以在那里设置一个断点并查看错误(如果成功则为 nil)、响应中的状态等。

我显然没有运行这个确切的代码,所以请原谅任何错别字,但是我经常使用这种方法从我的日常工作中加载和发送到各种后端。一般来说,它应该可以工作(并且,更重要的是,允许您弄清楚后端期望什么,假设您没有关于它的详细文档)。

编辑 :

好的,代码注释中的提示可能具有误导性:我的意思是检查响应是否有错误。 response对象(另请参阅 dataTask... 方法的一般文档)。我添加了一些帮助代码,但请注意 data 的转换将对象转换为 JSON 取决于您的服务器是否实际传递任何数据以及是否传递任何数据。或者它可能有一个奇怪的格式或其他东西,你需要弄清楚这一点。对于 POST 的简单内容,它可能不提供任何数据,您只需在 response 中获得有关它是否有效的相应信息。 .特别注意 NSHTTPURLResponsestatusCode属性(property)。除非你的服务器做了一些奇怪的事情,否则就是 HTTP status code由标准定义,应该可以帮助你。例如,如果您在请求中构建正文的方式(在我的示例代码中为 jsonBodyDict)是错误的(元素名称错误等),您将得到 400。

一般来说,您必须了解“错误”的含义在这里并不那么简单。这些方法将根本无法连接视为错误,因此在这些情况下,您会在完成块中获得一个错误对象。当您的服务器根本不存在或类似情况时,通常会出现这种情况。但是,如果您只是未能将您想要的信息传达给您的服务器,那么从 API 的角度来看,这不是错误,您也不会得到错误对象。您会收到一个有效的响应,指出“此请求是错误的”。在您的情况下,您已经做得很好,因为连接似乎已经发生并正常工作,您只是还没有发送服务器期望的数据。 response应该提供更多信息。

进一步调试这将超出这个问题的范围,因为最终我们正在讨论您的特定后端现在的行为方式。如果你无法弄清楚,你需要给我你的服务器的凭据,以便我可以自己测试,其他一切现在都由我来猜测。 :) 我们可以这样做,但最好在聊天中这样做,而不是在已经那么长的问题/答案中这样做,呵呵。

关于ios - Obj-C - POST JSON 数据到服务器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44814745/

有关ios - Obj-C - POST JSON 数据到服务器?的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  5. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  6. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  7. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  8. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  9. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  10. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

随机推荐