【问题标题】:AFNetworking POST gives no args or data, though GET worksAFNetworking POST 不提供参数或数据,尽管 GET 有效
【发布时间】:2014-07-02 17:55:05
【问题描述】:

我想将图像发布到服务器端 Flask 端点。我使用以下代码运行以下 GET 和 POST,然后描述服务器接收到的内容。如何确保服务器在 POST 请求中接收到图像和发布参数?

    [_client POST:@"post_image"
             parameters:parameters
             constructingBodyWithBlock:nil
             success:^(NSURLSessionDataTask *task, id responseObject) {
                 NSLog([responseObject description]);
             }
             failure:^(NSURLSessionDataTask *task, NSError *error) {
                 NSLog([error description]);
             }
     ];

   [_client GET:@"test_get"
     parameters:parameters
     success:^(NSURLSessionDataTask *task, id responseObject) {
         NSLog([responseObject description]);
     }
     failure:^(NSURLSessionDataTask *task, NSError *error) {
         NSLog([error description]);
     }
   ];

日志打印:

2014-07-02 10:29:06.883 lens-app[2808:60b] {
    code = "";
    data = "good stuff";
    error = "";
    success = 1;
}
2014-07-02 10:29:06.889 lens-app[2808:60b] {
    code = "";
    data = "good stuff";
    error = "";
    success = 1;
}

我使用这个 Flask 代码来描述服务器接收到的请求:

def print_request():
  print 'request'
  print str(request)
  print 'request.headers'
  print str(request.headers)
  print 'request.args'
  print str(request.args)
  print 'request.form'
  print str(request.form)
  print 'request.files'
  print str(request.files)
  print 'request.data'
  print str(request.data)
  print 'request.stream'
  print str(request.stream.read())
  print 'request.environ'
  print str(request.environ)
  print 'request.get_json()'
  print str(request.get_json())
  print 'row post body'
  print str(request.environ['body_copy'])

@app.route('/post_image', methods=['POST'])
def post_image():
  print_request()
  return json_response('good stuff')

@app.route('/test_get', methods=['GET'])
def test_get():
  print_request()
  return json_response('good stuff')

这是发布请求的结果:

request
<Request 'http://ec2-xyz.us-west-2.compute.amazonaws.com/post_image' [POST]>
request.headers
Transfer-Encoding: Chunked
Content-Length:
User-Agent: lens-app/1.0 (iPhone; iOS 7.1.1; Scale/2.00)
Connection: keep-alive
Host: ec2-xyz.us-west-2.compute.amazonaws.com
Accept: */*
Accept-Language: en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5
Content-Type: multipart/form-data; boundary=Boundary+F841C4764BD7CE95
Accept-Encoding: gzip, deflate


request.args
ImmutableMultiDict([])
request.form
ImmutableMultiDict([])
request.files
ImmutableMultiDict([])
request.data

request.stream

request.environ
{'wsgi.multiprocess': False, 'SERVER_SOFTWARE': 'Werkzeug/0.9.6', 'SCRIPT_NAME': '', 'HTTP_TRANSFER_ENCODING': 'Chunked', 'REQUEST_METHOD': 'POST', 'PATH_INFO': '/post_image', 'SERVER_PROTOCOL': 'HTTP/1.1', 'QUERY_STRING': '', 'werkzeug.server.shutdown': <function shutdown_server at 0x2c45c80>, 'CONTENT_LENGTH': '', 'HTTP_USER_AGENT': 'lens-app/1.0 (iPhone; iOS 7.1.1; Scale/2.00)', 'HTTP_CONNECTION': 'keep-alive', 'SERVER_NAME': '0.0.0.0', 'REMOTE_PORT': 44640, 'wsgi.url_scheme': 'http', 'SERVER_PORT': '80', 'werkzeug.request': <Request 'http://ec2-54-214-166-2.us-west-2.compute.amazonaws.com/post_image' [POST]>, 'body_copy': '', 'wsgi.input': <cStringIO.StringI object at 0x2be5ad0>, 'HTTP_HOST': 'ec2-xyz.us-west-2.compute.amazonaws.com', 'wsgi.multithread': False, 'HTTP_ACCEPT': '*/*', 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x7fccfbd3f1e0>, 'REMOTE_ADDR': '204.28.119.158', 'HTTP_ACCEPT_LANGUAGE': 'en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5', 'CONTENT_TYPE': 'multipart/form-data; boundary=Boundary+F841C4764BD7CE95', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate'}
request.get_json()
None
row post body

这是获取请求的结果:

request
<Request 'http://ec2-xyz.us-west-2.compute.amazonaws.com/test_get?up=what's&you=Hey' [GET]>
request.headers
Content-Length:
User-Agent: lens-app/1.0 (iPhone; iOS 7.1.1; Scale/2.00)
Connection: keep-alive
Host: ec2-xyz.us-west-2.compute.amazonaws.com
Accept: */*
Accept-Language: en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5
Content-Type:
Accept-Encoding: gzip, deflate


request.args
ImmutableMultiDict([('you', u'Hey'), ('up', u"what's")])
request.form
ImmutableMultiDict([])
request.files
ImmutableMultiDict([])
request.data

request.stream

request.environ
{'wsgi.multiprocess': False, 'SERVER_SOFTWARE': 'Werkzeug/0.9.6', 'SCRIPT_NAME': '', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/test_get', 'SERVER_PROTOCOL': 'HTTP/1.1', 'QUERY_STRING': 'up=what%27s&you=Hey', 'werkzeug.server.shutdown': <function shutdown_server at 0x2c45c08>, 'CONTENT_LENGTH': '', 'HTTP_USER_AGENT': 'lens-app/1.0 (iPhone; iOS 7.1.1; Scale/2.00)', 'HTTP_CONNECTION': 'keep-alive', 'SERVER_NAME': '0.0.0.0', 'REMOTE_PORT': 33553, 'wsgi.url_scheme': 'http', 'SERVER_PORT': '80', 'werkzeug.request': <Request 'http://ec2-xyz.us-west-2.compute.amazonaws.com/test_get?up=what's&you=Hey' [GET]>, 'body_copy': '', 'wsgi.input': <cStringIO.StringI object at 0x2be5ad0>, 'HTTP_HOST': 'ec2-xyz.us-west-2.compute.amazonaws.com', 'wsgi.multithread': False, 'HTTP_ACCEPT': '*/*', 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x7fccfbd3f1e0>, 'REMOTE_ADDR': '204.28.119.158', 'HTTP_ACCEPT_LANGUAGE': 'en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5', 'CONTENT_TYPE': '', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate'}
request.get_json()
None
row post body

【问题讨论】:

  • 首先要注意:您的 Content-Lenght 标头为空。这将阻止任何 POST 正文解析。

标签: ios flask afnetworking-2


【解决方案1】:

原来是 AFNetworking only supports streaming multipart POST requests。我正在使用 mod_wsgi 服务器端,并且只有 mod_wsgi 3.0+ 版本开始支持分块 HTTP 传输。以下是Changes in Version 3.0的mod_wsgi列表变化的评论:

  1. 现在允许分块的请求内容。此类内容将被分块并可供 WSGI 应用程序读取。请参阅:

http://code.google.com/p/modwsgi/issues/detail?id=1 启用此功能 功能,您必须使用:

WSGIChunkedRequest On 用于 Apache 配置中的适当上下文。

请注意,WSGI 在技术上无法支持 分块请求内容,无需所有分块请求内容 首先读入并缓冲。这是因为 WSGI 需要 当有任何请求内容时设置 CONTENT_LENGTH。

在 mod_wsgi 中没有缓冲。因此,为了能够读取请求 content 在分块传输编码的情况下,你需要一步 在 WSGI 规范之外做它说你不做的事情 意思是。

对于如何执行此操作,您有两种选择。你的第一选择 have 是在 wsgi.input 上调用 read() 但不提供任何参数 全部。这将导致读取并返回所有请求内容。

第二个是循环调用 wsgi.input 上的 read() 并设置块 size 作为参数传递并执行此操作,直到 read() 返回一个空 字符串。

因为在 WSGI 规范下这两种调用方法都是不允许的, 在使用这些你的代码将不能移植到其他 WSGI 主机 机制。

这是我使用的解决方法。我不使用 AFNetworking,所以我上传的图像没有流式传输。我找到了这个代码here

- (NSString *)uploadImageData:(NSData *)imageData toURL:(NSURL *)url withTitle:(NSString *)title {
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:url];

    // create a boundary to delineate the file
    NSString *boundary = @"14737809831466499882746641449";
    // tell the server what to expect
    NSString *contentType =
    [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];

    // make a buffer for the post body
    NSMutableData *body = [NSMutableData data];

    // add a boundary to show where the title starts
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary]
                      dataUsingEncoding:NSASCIIStringEncoding]];

    // add the title
    [body appendData:[
                      @"Content-Disposition: form-data; name=\"title\"\r\n\r\n"
                      dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[title
                      dataUsingEncoding:NSASCIIStringEncoding]];

    // add a boundary to show where the file starts
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary]
                      dataUsingEncoding:NSASCIIStringEncoding]];

    // add a form field
    [body appendData:[
                      @"Content-Disposition: form-data; name=\"image\"; filename=\"image.jpeg\"\r\n"
                      dataUsingEncoding:NSASCIIStringEncoding]];

    // tell the server to expect some binary
    [body appendData:[
                      @"Content-Type: application/octet-stream\r\n"
                      dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[
                      @"Content-Transfer-Encoding: binary\r\n"
                      dataUsingEncoding:NSASCIIStringEncoding]];
    [body appendData:[[NSString stringWithFormat:
                       @"Content-Length: %i\r\n\r\n", imageData.length]
                      dataUsingEncoding:NSASCIIStringEncoding]];

    // add the payload
    [body appendData:[NSData dataWithData:imageData]];

    // tell the server the payload has ended
    [body appendData:
     [[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary]
      dataUsingEncoding:NSASCIIStringEncoding]];

    // add the POST data as the request body
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:body];

    // now let's make the connection to the web
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    return [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 2017-08-22
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多