Volley + oauth-signpost로 POST 요청
17431 단어 안드로이드VolleyOAuthoauth-signpost
완성판의 플래그의 취급이 우선 그랬기 때문에 수정.
자작 Tumblr 클라이언트 앱의 통신 주위는, oauth-signpost를 사용한 자전 구현으로 하고 있었습니다.
그러나 에러 핸들링의 용이성과 단순하게 사용하고 싶다고 하는 이유로 구현을 Volley로 재작성하기 위한 조사를 실시했습니다.
역시 수요는 있는 것 같고, HurlStack를 확장해 OAuth의 서명을 하는 선인의 지혜를 몇개인가 찾아낼 수 있었습니다.
Android - Volley + oauth-signpost에서 OAuth 요청 - Qiita
그러나 이러한 HurlStack 확장은 GET 요청에 대해 효과적으로 작동하지만이 방법으로 POST 요청을하면 401이 돌아옵니다.
E/Volley﹕ [46076] BasicNetwork.performRequest: Unexpected response code 401 for http://api.tumblr.com/v2/blog/hogehoge.tumblr.com/post/reblog
문제
POST 요청의 경우, 서명하기 전에 consumer에 POST 파라미터 등을 건네줄 필요가 있습니다만, 앞의 예에서는 열린 커넥션에 바로 서명하고 있기 때문에 파라미터가 부족한 상태입니다.
그래서 앞서 언급한 HurlStack 확장을 수정해 나가겠습니다만, 이것이 의외로 고생했습니다.
먼저 POST 요청을 서명할 때 요청 매개 변수가 필요하지만 위에서 설명한 HurlStack 확장이 서명하는
createConnection
메서드는 Volley 요청을 참조할 수 없습니다.그럼, 다른 메소드는 어떨지라고 확인하면(자), 원래 Override 가능한 것은
createConnection
이외에는 performRequest
뿐입니다.그런 다음
performRequest
에는 Volley 요청이 인수로 전달됩니다.그래서이 두 가지 방법을 Override하여 POST 요청을 서명하는 방법을 생각해 봅시다.
시행착오
HurlStack.java - platform/frameworks/volley - Git at Google
HurlStack.java를 읽으면
performRequest
에서 createConnection
를 호출하여 연결을 생성하는 것 같습니다.그래서 Volley 요청이 인수로 전달되는
performRequest
내에서 OAuth에 대한 매개 변수를 consumer로 설정하는 방법을 시도해 보겠습니다.또한 protected
Request#getParams()
에 액세스하기 위해 자체 패키지의 Request 확장으로 캐스팅합니다.public class OAuthPostHurlStack extends HurlStack {
private final OAuthConsumer mConsumer;
public OAuthPostHurlStack(OAuthConsumer consumer) {
mConsumer = consumer;
}
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
if (request.getMethod() == Request.Method.POST) {
if (request instanceof CustomRequest) {
// POSTパラメータをHttpParametersに詰め替える
HttpParameters oauthParams = new HttpParameters();
Map<String, String> params = ((CustomRequest) request).getParams();
for (String key : params.keySet()) {
oauthParams.put(key, OAuth.percentEncode(params.get(key)));
}
// POSTパラメータに加えてエンドポイントのURLも必要
oauthParams.put("realm", request.getUrl());
// consumerのパラメータとして設定
mConsumer.setAdditionalParameters(oauthParams);
}
}
return super.performRequest(request, additionalHeaders);
}
@Override
protected HttpURLConnection createConnection(URL url) throws IOException {
// 最初に紹介した先人のものと一緒なので省略
return connection;
}
}
이것으로 잘 작동합니까? 라고 생각해 실행해 보는 또 다시 401 에러…뭔가 부족하다…
E/Volley﹕ [46076] BasicNetwork.performRequest: Unexpected response code 401 for http://api.tumblr.com/v2/blog/hogehoge.tumblr.com/post/reblog
해결
다시 한번, 자신의 구현과 HurlStack.java를 비교해 알 수 없는 설정이 없는지 확인해 보면, 자신의 구현에서는 서명 전에, HttpURLConnection의
setRequestMethod("POST")
와 setDoOutput(true)
를 불렀습니다.원래의 HurlStack.java에서는, 당연합니다만 이 처리는
createConnection
보다 뒤에서 행해지고 있습니다.이때 HurlStack을 확장하는 것이 아니라 원래부터 다시 쓸까 하고 일순간 머리를 넘어섰습니다만, 이 2개의 처리는 본래의 처리전에 1회 실행해 버려도 문제 없을 것이라고 판단 서명으로 설정하기로 결정했습니다.
public class OAuthPostHurlStack extends HurlStack {
private final OAuthConsumer mConsumer;
private ArrayList<String> mOauthSignedPosts = new ArrayList<>();
public OAuthPostHurlStack(OAuthConsumer consumer) {
mConsumer = consumer;
}
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
if (request.getMethod() == Request.Method.POST) {
if (request instanceof CustomRequest) {
// OAuthで署名すべきPOSTリクエストのURLを格納する
mOauthSignedPosts.add(request.getUrl());
// POSTパラメータをHttpParametersに詰め替える
HttpParameters oauthParams = new HttpParameters();
Map<String, String> params = ((CustomRequest) request).getParams();
for (String key : params.keySet()) {
oauthParams.put(key, OAuth.percentEncode(params.get(key)));
}
// POSTパラメータに加えてエンドポイントのURLも必要
oauthParams.put("realm", request.getUrl());
// consumerのパラメータとして設定
mConsumer.setAdditionalParameters(oauthParams);
}
}
return super.performRequest(request, additionalHeaders);
}
@Override
protected HttpURLConnection createConnection(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
if (mOauthSignedPosts.contains(url)) {
// POSTリクエストのコネクションは署名前に設定が必要
connection.setRequestMethod("POST");
connection.setDoOutput(true);
mOauthSignedPosts.remove(url)
}
mConsumer.sign(connection);
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
return connection;
}
}
이제 무사히 POST 요청도 서명할 수 있었습니다.
요약
oauth-signpost에서 HttpURLConnection의 POST 요청을 서명할 때는 서명하기 전에 다음 두 점이 필요합니다.
setRequestMethod("POST")
및 setDoOutput(true)
설정 이것, 한 번 스스로 oauth-signpost 사용한 실장하고 있었기 때문에 알았지만, 하지 않았다면 도중에 좌절했을 것이다…
이번에 만든 것은 Gists에도 올리고 있습니다.
OAuth signed POST request with Volley + oauth-signpost
자작의 Tumblr 클라이언트도 Google Play에서 공개하고 있으므로 잘 부탁드립니다.
Reference
이 문제에 관하여(Volley + oauth-signpost로 POST 요청), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/chibatching/items/d9e81a391731e3c51fd9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)