我正在编写一个Android应用程序,它是我的Web应用程序的客户端。我正在尝试使用RoboSpice来执行网络请求。
首先,我决定测试API调用以获取OAuth2令牌。可以调用以下curl命令从命令行获取它:
curl -X POST -d "grant_type=password&username=user&password=pass" http://testid:testsecret@localhost:8000/oauth2/token/
user
和pass
是注册用户的凭据,testid
和testsecret
是我的网络应用中注册的应用的ID和秘密。此调用返回带有标记和其他参数的JSON对象。
我正在尝试使用RoboSpice执行相同的请求。这是我为请求编写的代码:
public class OAuth2Request extends SpringAndroidSpiceRequest<String> {
private final String user;
private final String pass;
public OAuth2Request(String user, String pass) {
super(String.class);
setRestTemplate(new RestTemplate());
getRestTemplate().getMessageConverters().add(new StringHttpMessageConverter());
this.user = user;
this.pass = pass;
}
@Override
public String loadDataFromNetwork() throws RestClientException {
String client_id = "testid";
String client_secret = "testsecret";
HttpBasicAuthentication authHeader = new HttpBasicAuthentication(client_id, client_secret);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(authHeader);
requestHeaders.setUserAgent("AndroidNotesApp/1.0");
String data = String.format("grant_type=password&username=%s&password=%s", this.user, this.pass);
HttpEntity<String> requestEntity = new HttpEntity<>(data, requestHeaders);
String url = "http://10.0.2.2:8000/oauth2/token/";
return getRestTemplate().postForObject(url, requestEntity, String.class);
}
}
我的活动中的SpiceManager
声明为:
protected SpiceManager spiceManager = new SpiceManager(JacksonSpringAndroidSpiceService.class);
并且请求由以下行组成:
OAuth2Request req = new OAuth2Request(user, pass);
spiceManager.execute(req, new OAuth2RequestListener());
user
和pass
是String
个,它们从EditText
次观看中获取其值。
但是当我尝试运行此请求时,我收到异常400 BAD REQUEST
。
我在我的django应用程序中设置了登录来打印/oauth2/token/
的请求,我看到这个请求中的POST参数是空的(我希望它们与curl请求中的相同,类似于{ {1}})。
为什么在RoboSpice请求的情况下POST参数为空?我做错了什么?
P.S。以防万一:我的django Web应用程序中的oauth2身份验证是使用DjangoOAuthToolkit和DjangoRestFramework实现的。
UPDATE :我决定在我的django Web应用程序之前设置nginx代理以记录请求正文。我从Android应用程序获得的请求正文如下:
{'grant_type': 'password', 'password': 'pass', 'username': 'user'}
所以奇怪的\x22grant_type=password&username=user&password=pass\x22
符号被添加到正文的开头和结尾(我相信它是双引号\x22
符号,但我不确定)。似乎这些"
搞砸了django中的POST参数解析。我怎样才能摆脱这些符号?
答案 0 :(得分:1)
我设法解决了我的问题,所以我发布了一个答案,以防有人帮忙。
默认情况下, SpringAndroidSpiceRequest
尝试将java对象映射到JSON,因此当我尝试在请求体中发送String
时,它将其用双引号括起来使其成为JSON字符串。我不需要将请求主体作为JSON字符串发送,为此,我需要定义其他消息转换器。
奇怪的是,构造函数中的这些行似乎没有做任何事情
setRestTemplate(new RestTemplate());
getRestTemplate().getMessageConverters().add(new StringHttpMessageConverter());
当我使用调试器时,它只显示了一个消息转换器MappingJacksonHttpMessageConverter
。所以我决定在loadDataFromNetwork
方法中添加自己的消息转换器。
我需要两个邮件转换器:FormHttpMessageConverter
,它将处理请求并从MultiValueMap
发出请求POST正文,而MappingJacksonHttpMessageConverter
则会将JSON响应处理为OAuth2Token
我也宣称过POJO。
我相信,对于使用客户端(POST普通字符串和接收纯字符串)对REST API进行简单测试,除了SpiceRequest
之外,最好为SpringAndroidSpiceRequest
选择另一种实现,但是我决定坚持使用它,因为它更容易为我的Web应用程序实现完整的客户端。
OAuth2Request
的完整代码:
public class OAuth2Request extends SpringAndroidSpiceRequest<OAuth2Token> {
private final String user;
private final String pass;
public OAuth2Request(String user, String pass) {
super(OAuth2Token.class);
this.user = user;
this.pass = pass;
}
@Override
public OAuth2Token loadDataFromNetwork() throws RestClientException {
String client_id = "testid";
String client_secret = "testsecret";
HttpBasicAuthentication authHeader = new HttpBasicAuthentication(client_id, client_secret);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAuthorization(authHeader);
requestHeaders.setUserAgent("AndroidNotesApp/1.0");
MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
data.add("grant_type", "password");
data.add("username", this.user);
data.add("password", this.pass);
HttpEntity<?> requestEntity = new HttpEntity<>(data, requestHeaders);
String url = "http://10.0.2.2:8000/oauth2/token/";
getRestTemplate().getMessageConverters().clear();
getRestTemplate().getMessageConverters().add(new FormHttpMessageConverter());
getRestTemplate().getMessageConverters().add(new MappingJacksonHttpMessageConverter());
return getRestTemplate().postForObject(url, requestEntity, OAuth2Token.class);
}
}