在 Objective-c 中使用 GTMHTTPFetcher POST 将 GPX 文件上传到 Strava API
Uploading GPX file to Strava API with GTMHTTPFetcher POST in Objective-c
在探索了 Strava API (http://strava.github.io/api/v3) 与 GTMHTTPFetcher 的使用 2 天后,我现在完全无法将 .gpx 文件上传到我的帐户,所以我决定询问在这里寻找答案。我成功接收并存储了一个具有必要 'view_private,write' 权限的访问令牌,服务器正在响应请求,我设法接收和更改存储在我帐户中的数据。尝试上传 .gpx (xml) 文件时出现错误(错误请求):
The operation couldn’t be completed. (com.google.HTTPStatus error 400.)
对于构建 HTTP POST 请求,我显然有些不明白,我尝试了不同的方法来试验 http header 中的值,更改了获取 url在“/上传?”之后使用 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
如果您收到 HTTP 400,则表示 Strava V3 API 拒绝了您的请求 - 通常来自上传端点的 400 包含有关错误信息的响应信息。我将从检查错误响应的响应主体开始。我不熟悉 GTMHTTPFetcher,但您应该能够调试和观察响应主体,或者您可以使用 Charles Proxy 之类的工具来调试请求和响应。尝试比较 curl
请求和来自您的 Objective-C 代码的请求。
Strava V3 上传 API 期望上传的文件部分在 file
参数中 - 同样,在不熟悉 GTMHTTPFetcher 的情况下,我不能确定它在做什么,但您似乎没有指定文件数据是名为 file
.
的 multipart/form-data
部分的一部分
远景:你似乎也在混合 POST 正文和查询字符串参数,所以你的 data_type
参数 可能 没有它通过。我会保持一致并将所有参数放在 POST 正文中。
所以我自己格式化了正文,并且在下面的示例的帮助下了解了如何完成此操作 link:http://nthn.me/posts/2012/objc-multipart-forms.html. I experienced troubles with the last boundary though because it needed an extra --
afterwards which was missing in the example. Luckily I found out about this quickly because I was reading up about the multipart HTTP POST protocol here: 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:)];
现在服务器响应 "Your activity is still being processed.",我看到地图已到达我在 Strava 上的帐户。
我确信 GTMHTTPFetcher 能够提供更容易 read/handle 的解决方案,但我还没有找到它,这个解决方案令人满意。
在探索了 Strava API (http://strava.github.io/api/v3) 与 GTMHTTPFetcher 的使用 2 天后,我现在完全无法将 .gpx 文件上传到我的帐户,所以我决定询问在这里寻找答案。我成功接收并存储了一个具有必要 'view_private,write' 权限的访问令牌,服务器正在响应请求,我设法接收和更改存储在我帐户中的数据。尝试上传 .gpx (xml) 文件时出现错误(错误请求):
The operation couldn’t be completed. (com.google.HTTPStatus error 400.)
对于构建 HTTP POST 请求,我显然有些不明白,我尝试了不同的方法来试验 http header 中的值,更改了获取 url在“/上传?”之后使用 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
如果您收到 HTTP 400,则表示 Strava V3 API 拒绝了您的请求 - 通常来自上传端点的 400 包含有关错误信息的响应信息。我将从检查错误响应的响应主体开始。我不熟悉 GTMHTTPFetcher,但您应该能够调试和观察响应主体,或者您可以使用 Charles Proxy 之类的工具来调试请求和响应。尝试比较 curl
请求和来自您的 Objective-C 代码的请求。
Strava V3 上传 API 期望上传的文件部分在 file
参数中 - 同样,在不熟悉 GTMHTTPFetcher 的情况下,我不能确定它在做什么,但您似乎没有指定文件数据是名为 file
.
multipart/form-data
部分的一部分
远景:你似乎也在混合 POST 正文和查询字符串参数,所以你的 data_type
参数 可能 没有它通过。我会保持一致并将所有参数放在 POST 正文中。
所以我自己格式化了正文,并且在下面的示例的帮助下了解了如何完成此操作 link:http://nthn.me/posts/2012/objc-multipart-forms.html. I experienced troubles with the last boundary though because it needed an extra --
afterwards which was missing in the example. Luckily I found out about this quickly because I was reading up about the multipart HTTP POST protocol here: 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:)];
现在服务器响应 "Your activity is still being processed.",我看到地图已到达我在 Strava 上的帐户。
我确信 GTMHTTPFetcher 能够提供更容易 read/handle 的解决方案,但我还没有找到它,这个解决方案令人满意。