【发布时间】:2016-05-31 18:44:38
【问题描述】:
我正在尝试将我的 android 应用程序连接到 shutterstock api,以便它可以在那里搜索一些图像。它使用 https 方案 + 基本身份验证标头来允许用户进行所有搜索请求。我使用 HttpsURLConnection 在常规 Java 项目中实现了该功能,并且能够获得正确的 JSON 响应。 java代码如下所示:
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();//proxy);
String username = "62c01aa824222683004b", password = "dc4ad748a75e4e69ec853ad2435a62b700e66164";
String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes("UTF-8"));
System.out.println(encoded.equals("Nj0jMDFhZWE4ZmE4MjY4MzAwNGI6ZGM0YWQ3NDhhNzVlNGU2gWVjODUzYWQ0ZmEzYTYyYjc7MGU2NjE2NA==")); // prints true
urlConnection.setRequestProperty("Authorization", "Basic "+encoded);
将其移植到 Android 时,它会抛出带有 401 错误代码的 IOException。正如许多关于 SO 的帖子(如 here)中所解释的那样,我相应地修改了代码,并添加了一个额外的 try-catch,如下所示:
String username = "62c01aa824222683004b", password = "dc4ad748a75e4e69ec853ad2435a62b700e66164", encoded = "";
encoded = Base64.encodeToString((username+":"+password).getBytes("UTF-8"), Base64.URL_SAFE);
Log.e("test", "encoded strings match:" + encoded.equals("Nj0jMDFhZWE4ZmE4MjY4MzAwNGI6ZGM0YWQ3NDhhNzVlNGU2gWVjODUzYWQ0ZmEzYTYyYjc7MGU2NjE2NA==") + "\n" + encoded); // prints false but string is same!!
URL url = new URL(reqUrl);
connection = (HttpsURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic "+encoded);
try {
if (connection != null) {
connection.connect();
if (200 == connection.getResponseCode()) { // ---> throws IOException
BufferedReader br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
String output;
while ((output = br.readLine()) != null) {
Log.e("test", output);
response.append(output);
}
connection.disconnect();
return response.toString();
}
}
} catch (IOException e) {
try {
Log.e("test", e.getMessage()); // ---> prints "No authentication challenges found"
Log.e("test", connection.getResponseCode() + ":" + connection.getResponseMessage() + connection.getHeaderFields());
//---> prints 401:Unauthorized{null=[HTTP/1.1 401 Unauthorized], cache-control=[no-cache], Connection=[keep-alive], Content-Length=[38], Content-Type=[application/json; charset=utf8], Date=[Tue, 31 May 2016 14:11:28 GMT], Server=[nginx], X-Android-Received-Millis=[1464703888222], X-Android-Sent-Millis=[1464703887592], x-end-user-request-id=[f754ec7f-c344-431b-b641-360aabb70184], x-shutterstock-app-version=[apitwo-625], x-shutterstock-resource=[/v2/images/search]}
if (401 == connection.getResponseCode()) {
InputStream es = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(es));
String output;
while ((output = br.readLine()) != null) {
Log.e("test", output); // ---> prints {"message":"Invalid auth credentials"}
response.append(output);
}
connection.disconnect();
return response.toString();
} else {
Log.e("test","Could not connect! " + connection.getResponseCode() + ":" + connection.getResponseMessage() + ". " + connection.getRequestMethod());
}
}catch (Exception e1){e1.printStackTrace();}
}
我无法检查 Firefox 的 Rest 客户端中的响应标头,因为当我添加身份验证标头时它不会将请求发送到服务器。
所以这里的问题是:
- 这是在 Android 中处理 401 错误的正确方法吗?我会在内部 try-catch 中获得 JSON 响应吗?
- java 程序使用与 Android 中完全相同的编码字符串。为什么 String.equals() 在 java 中返回“true”而在 android 中返回“false”?
- 来自服务器的错误消息显示“无效的身份验证凭据”。 Android 和 Java 之间的编码字符串是否因任何原因而不同?如果是,那么第 2 点是有道理的。
【问题讨论】:
-
1) 做 web 请求的正确方法是使用库(比较 github.com/BitFountain/ShutterDroid/blob/master/app/src/main/… ),HttpUrlConnection 非常复杂:tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection 2) 不同的字符串,equals 方法保证在 pc 和 android 上是一样的 3) 我想是的。
-
@zapl - 感谢关于使用库的建议。我第一次使用 HttpClient 并遇到了同样的问题。所以尝试使用HUC。我猜 equals 方法在 PC 和 Android 上完美地完成了它的工作。但是在Android中出现“错误”的原因是没有意义的。我将编码后的字符串从 PC 复制到字符串中,瞧!它起作用了;)
标签: java android authentication https