Java HttpURLConnection c=URL.openConnection();c、 setRequestProperty()不';行不通
这里的代码是一个普通的Java应用程序,而不是android应用程序,它被设计为以开发者身份使用auth_密钥向设备发送C2DM消息,问题如下所述Java HttpURLConnection c=URL.openConnection();c、 setRequestProperty()不';行不通,java,httpurlconnection,android-c2dm,Java,Httpurlconnection,Android C2dm,这里的代码是一个普通的Java应用程序,而不是android应用程序,它被设计为以开发者身份使用auth_密钥向设备发送C2DM消息,问题如下所述 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
public class C2DMSendMessage {
private final static String AUTH = "authentication";
private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
public static final String PARAM_REGISTRATION_ID = "registration_id";
public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
public static final String PARAM_COLLAPSE_KEY = "collapse_key";
private static final String UTF8 = "UTF-8";
// Registration is currently hardcoded
private final static String YOUR_REGISTRATION_STRING = "APA91bGf8gkFMn_sBP_hosSAiqUmmLwOdIqVSQKbbqXv2WSADQ51gbixInAGUk1U_vDIcz7izVaq6tvu8KXGsiQ7BIKy_7f04id00SUms8h3YGxbsKd6Jjg";
public static void main(String[] args) throws Exception {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
// TODO Auto-generated method stub
return true;
}
});
String auth_key = "DQAAAA4BAADAb7BDi6KY9pj11ERiY0R1TaEynLK6AtSPxzzIeCih_VDyWLhEJCvmkXjh6gRAsGpLb0wtAGmWIK9CjsBMT3upjnZ86tRYnvfOknkN45ORk29AsR2he-JEo1Y4eVcUutoPnBbIX2kzoEeY2ULYXyOQix7oWSWb4CJS3XYrb7qcmQxMv3yiIAF8kO0Sav7-NspCSI3tV3lISrz_BWqSCVGHWxT6KZ_PZwjH7442CpMfZhOYxsgDanQod8EypHjHmNQK_txWwFeiFj66jsi90BpyPKvUX_ZUbOmSKVZP3gBcKrK9iSnJrSUpLuEN46NGRzl2uBg9I9V-wJuFBgG1aBXqA1oWFdkEewxwXapuVqR1-g";
// Send a sync message to this Android device.
StringBuilder postDataBuilder = new StringBuilder();
postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
.append(YOUR_REGISTRATION_STRING);
// if (delayWhileIdle) {
// postDataBuilder.append("&").append(PARAM_DELAY_WHILE_IDLE)
// .append("=1");
// }
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
.append("0");
postDataBuilder.append("&").append("data.payload").append("=")
.append(URLEncoder.encode("Lars war hier", UTF8));
byte[] postData = postDataBuilder.toString().getBytes(UTF8);
// Hit the dm URL.
URL url = new URL("https://android.clients.google.com/c2dm/send");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",
Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="
+ auth_key);
System.out.println(conn.getRequestProperties());
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int responseCode = conn.getResponseCode();
System.out.println(String.valueOf(responseCode));
// Validate the response code
if (responseCode == 401 || responseCode == 403) {
// The token is too old - return false to retry later, will
// fetch the token
// from DB. This happens if the password is changed or token
// expires. Either admin
// is updating the token, or Update-Client-Auth was received by
// another server,
// and next retry will get the good one from database.
System.out.println("Unauthorized - need token");
}
// Check for updated token header
String updatedAuthToken = conn.getHeaderField(UPDATE_CLIENT_AUTH);
if (updatedAuthToken != null && !auth_key.equals(updatedAuthToken)) {
System.out.println("Got updated auth token from datamessaging servers: "
+ updatedAuthToken);
}
String responseLine = new BufferedReader(new InputStreamReader(
conn.getInputStream())).readLine();
// NOTE: You *MUST* use exponential backoff if you receive a 503
// response code.
// Since App Engine's task queue mechanism automatically does this
// for tasks that
// return non-success error codes, this is not explicitly
// implemented here.
// If we weren't using App Engine, we'd need to manually implement
// this.
if (responseLine == null || responseLine.equals("")) {
System.out.println("Got " + responseCode
+ " response from Google AC2DM endpoint.");
throw new IOException(
"Got empty response from Google AC2DM endpoint.");
}
String[] responseParts = responseLine.split("=", 2);
if (responseParts.length != 2) {
System.out.println("Invalid message from google: " + responseCode
+ " " + responseLine);
throw new IOException("Invalid response from Google "
+ responseCode + " " + responseLine);
}
if (responseParts[0].equals("id")) {
System.out.println("Successfully sent data message to device: "
+ responseLine);
}
if (responseParts[0].equals("Error")) {
String err = responseParts[1];
System.out.println("Got error response from Google datamessaging endpoint: "
+ err);
// No retry.
throw new IOException(err);
}
}
}
在上面的代码中,我试图发送一条C2DM消息,但这与此无关
URL url = new URL("https://android.clients.google.com/c2dm/send");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="+ auth_key);
System.out.println(conn.getRequestProperties());
在我重复的部分中,我试图设置其中的3个请求属性,但只有1个到达conn中的hashmap
这是输出:
{Content Type=[application/x-www-form-urlencoded;charset=UTF-8]}
我不明白,如果代码是独立运行的,那么代码怎么能运行呢
而不是作为更大代码的一部分工作
我还尝试了addRequestProperty
提前感谢使用setFixedLengthStreamingMode(postData.Length),而不是在请求属性中设置内容长度 根据的来源,内容长度是一个“受限标题”:
因此,即使您设置了授权标题,在查询标题时也不会返回该标题。内容长度是自动设置的。你不能自己直接设置。但是,在设置固定长度流模式时,您可以传递正确的长度。我也遇到了同样的问题,您可以在代码中添加这一行来解决它
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
为此,使用方法setFixedLengthStreamingMode。JavaDoc中写道:“当内容长度事先已知时,此方法用于启用HTTP请求正文的流式传输,而无需内部缓冲。”我将其删除,但授权从未真正进入请求属性Gain,您将无法读回它……出于安全原因,java运行时中的实现限制了该头。使用协议嗅探器(如Fiddler)检查流量。您应该会在流量中看到授权标头。我将内容长度行替换为conn.setFixedLengthStreamingMode(postdata.length);输出仍然是请求属性:{Content Type=[application/x-www-form-urlencoded;charset=UTF-8]}请求属性中从未输入过授权:/,请注意,我还尝试了在我使用的import java.net.HttpURLConnection代码中不设置所有代码的长度;不是sun httpurl,eclipse只是不使用sun One HttpURLConnection不允许您设置内容长度,也不会向您报告。在属性映射中明确排除了返回授权。我已经更新并扩展了我的原始答案,添加了一些注释。“sun httpurl”是使用股票Java虚拟机时HttpURLConnection的实现委托类。如果您在Eclipse中使用setRequestProperty方法,它最终将访问此实现委托。这就是我找到答案的原因。我不知道为什么,但我的代码不起作用,而stackoverflow上发布的另一个代码也不起作用,我将尝试其他选择,但就我而言,你的答案是正确的,谢谢
249 // the following http request headers should NOT have their values
250 // returned for security reasons.
251 private static final String[] EXCLUDE_HEADERS = {
252 "Proxy-Authorization",
253 "Authorization"
254 };
255
256 // also exclude system cookies when any might be set
257 private static final String[] EXCLUDE_HEADERS2= {
258 "Proxy-Authorization",
259 "Authorization",
260 "Cookie",
261 "Cookie2"
262 };
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");