使用Objective-c中的GTMHTTPFetcher POST将GPX文件上传到Strava API

时间:2015-05-29 16:26:20

标签: ios objective-c http post xmlhttprequest

在探索使用Strava API(http://strava.github.io/api/v3)和GTMHTTPFetcher 2天后,我现在完全停止将.gpx文件上传到我的帐户,所以我决定在这里要求答案。我成功接收并存储了具有必要的'view_private,write'权限的访问令牌,服务器正在响应请求,我设法接收并更改存储在我帐户中的数据。当尝试上传.gpx(xml)文件时,我收到错误(错误请求):

  

无法完成操作。 (com.google.HTTPStatus错误400。)

显然我有一些关于构建HTTP POST请求的不明白的事情,我尝试了不同的方法来试验http标头中的值,更改了'/ uploads'之后的获取网址?与file = ...等无济于事。对于身份验证,我使用GTMOAuth2Authentication。

我的代码:

- (void) uploadToStrava {

    NSString *filePath = @"somefilepath.gpx";
    NSURL *url = [NSURL URLWithString:@"https://www.strava.com/api/v3/uploads?data_type=gpx"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:[NSData dataWithContentsOfFile:filePath]];

    [self.signedStravaAuth authorizeRequest:request];

    GTMHTTPFetcher* myStravaFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
    [myStravaFetcher beginFetchWithDelegate:self
                          didFinishSelector:@selector(myStravaFetcher:finishedWithData:error:)];
    self.currentFetcher = myStravaFetcher;

}

- (void) myStravaFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data error:(NSError *) error {
    if (error != nil) {
        [self handleErrorWithText:nil];
        NSLog(@"error %@", [error localizedDescription]);
    } else {
        NSString *info = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
        NSDictionary *result = [self.jsonParser objectWithString:info];
        NSLog(@"Strava response: %@", result);
    }
}

API文档在CURL中附带以下示例请求:

$ curl -X POST https://www.strava.com/api/v3/uploads \
    -H "Authorization: Bearer 83ebeabdec09f6670863766f792ead24d61fe3f9" \
    -F activity_type=ride \
    -F file=@test.fit \
    -F data_type=fit

相关问题:Using AFNetworking to POST a file asynchronously with upload progress to Strava V3 API

2 个答案:

答案 0 :(得分:1)

如果您收到HTTP 400,则意味着Strava V3 API拒绝您的请求 - 通常上传端点的400s包含响应中有关错误的信息。我将首先检查您的错误响应的响应正文。我不熟悉GTMHTTPFetcher,但您应该能够调试并观察响应正文,或者您可以使用Charles Proxy之类的工具来调试请求和响应。尝试比较curl请求和来自Objective-C代码的请求。

Strava V3上传API期望上传的文件部分位于file参数中 - 再次,不熟悉GTMHTTPFetcher我无法确定它在做什么,但它没有&您似乎在指定文件数据是名为multipart/form-data的{​​{1}}部分的一部分。

长镜头:您似乎正在混合POST正文和查询字符串参数,因此您的file参数可能无法通过。我保持一致并将所有参数放在POST体内。

答案 1 :(得分:1)

所以我自己对身体进行了格式化,并通过以下链接中的示例了解了如何完成此操作:http://nthn.me/posts/2012/objc-multipart-forms.html。我遇到了最后一个边界的麻烦,因为之后需要一个额外的--,这在示例中是遗漏的。幸运的是,我很快就发现了这一点,因为我在这里阅读了多部分HTTP POST协议:http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html

    NSURL *url = [NSURL URLWithString:@"https://www.strava.com/api/v3/uploads"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];

    NSString *boundary = @"YOUR_BOUNDARY_STRING";
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request addValue:contentType forHTTPHeaderField:@"Content-Type"];

    NSMutableData *body = [NSMutableData data];

    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", usefullFileName] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[NSData dataWithContentsOfFile:filePath]];

    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"data_type\"\r\n\r\n%@", @"gpx"] dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"name\"\r\n\r\n%@", @"Some Name"] dataUsingEncoding:NSUTF8StringEncoding]];

    [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [request setHTTPBody:body];
    NSString *strData = [[NSString alloc]initWithData:body encoding:NSUTF8StringEncoding];
    NSLog(@"%@", strData); // human readable body in log

    [self.signedStravaAuth authorizeRequest:request];

    GTMHTTPFetcher* myStravaFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
    [myStravaFetcher beginFetchWithDelegate:self
                         didFinishSelector:@selector(myStravaFetcher:finishedWithData:error:)];

现在服务器响应“您的活动仍在处理中”。我看到地图到达Strava的帐户。

我确信GTMHTTPFetcher能够提供更易于阅读/处理的解决方案,但我还没有找到它,这个解决方案令人满意。