AndroidおよびRestTemplateを介して接続しようとしているRESTful APIがあります。 APIへのすべてのリクエストは、HttpEntityのヘッダーを設定し、RestTemplateのexchange()
メソッドを使用して、HTTP認証で認証されます。
すべてのGETリクエストはこのようにうまく機能しますが、認証されたPOSTリクエストをどのように達成するかわかりません。 postForObject
およびpostForEntity
はPOSTを処理しますが、認証ヘッダーを設定する簡単な方法はありません。
GETの場合、これは非常に効果的です。
HttpAuthentication httpAuthentication = new HttpBasicAuthentication("username", "password");
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(httpAuthentication);
HttpEntity<?> httpEntity = new HttpEntity<Object>(requestHeaders);
MyModel[] models = restTemplate.exchange("/api/url", HttpMethod.GET, httpEntity, MyModel[].class);
しかし、POSTはexchange()
では機能しないようです。カスタマイズされたヘッダーを送信しないため、exchange()
を使用してリクエスト本文を設定する方法がわかりません。
RestTemplateから認証済みPOSTリクエストを作成する最も簡単な方法は何ですか?
答えは見つかりました。 exchange()
が最善の方法です。奇妙なことに、HttpEntity
クラスにはsetBody()
メソッドがありません(getBody()
があります)が、コンストラクターを介してリクエスト本文を設定することはまだ可能です。
// Create the request body as a MultiValueMap
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
body.add("field", "value");
// Note the body object as first parameter!
HttpEntity<?> httpEntity = new HttpEntity<Object>(body, requestHeaders);
MyModel model = restTemplate.exchange("/api/url", HttpMethod.POST, httpEntity, MyModel.class);
少し異なるアプローチ:
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("HeaderName", "value");
headers.add("Content-Type", "application/json");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<ObjectToPass> request = new HttpEntity<ObjectToPass>(objectToPass, headers);
restTemplate.postForObject(url, request, ClassWhateverYourControllerReturns.class);
JavaからREST呼び出しを行っている間に過去の認証を取得しようとしていたときに、最近この問題に対処していました。そして、それを機能させることに関係するエラー。
私のために働いたのは、Base64
で資格情報をエンコードし、基本認証ヘッダーとして追加することでした。次に、それらをHttpEntity
としてrestTemplate.postForEntity
に追加し、必要な応答を提供しました。
これを完全に記述したクラスを以下に示します(RestTemplateを拡張)。
public class AuthorizedRestTemplate extends RestTemplate{
private String username;
private String password;
public AuthorizedRestTemplate(String username, String password){
this.username = username;
this.password = password;
}
public String getForObject(String url, Object... urlVariables){
return authorizedRestCall(this, url, urlVariables);
}
private String authorizedRestCall(RestTemplate restTemplate,
String url, Object... urlVariables){
HttpEntity<String> request = getRequest();
ResponseEntity<String> entity = restTemplate.postForEntity(url,
request, String.class, urlVariables);
return entity.getBody();
}
private HttpEntity<String> getRequest(){
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + getBase64Credentials());
return new HttpEntity<String>(headers);
}
private String getBase64Credentials(){
String plainCreds = username + ":" + password;
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
return new String(base64CredsBytes);
}
}
非常に便利なのは、リクエストxml自体がPOSTの本体であり、パラメータではないというわずかに異なるシナリオでした。そのためには、次のコードを使用できます-同様の問題を抱えている他の誰かが恩恵を受ける場合に備えて、回答として投稿してください。
final HttpHeaders headers = new HttpHeaders();
headers.add("header1", "9998");
headers.add("username", "xxxxx");
headers.add("password", "xxxxx");
headers.add("header2", "yyyyyy");
headers.add("header3", "zzzzz");
headers.setContentType(MediaType.APPLICATION_XML);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
final HttpEntity<MyXmlbeansRequestDocument> httpEntity = new HttpEntity<MyXmlbeansRequestDocument>(
MyXmlbeansRequestDocument.Factory.parse(request), headers);
final ResponseEntity<MyXmlbeansResponseDocument> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity,MyXmlbeansResponseDocument.class);
log.info(responseEntity.getBody());