This Code here is a normal Java application not an android application, this is designed to send C2DM messages to a device with YOUR_REGISTRATION_STRING as the developer with auth_key, the problem is described below
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);
}
}
}
in the code above i'm attempting to send a C2DM Message but it's irrelevant
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());
in the portion that i have repeated i am attempting to set request properties 3 of them but only 1 ever reaches the hashmap in conn this is the output :
{Content-Type=[application/x-www-form-urlencoded;charset=UTF-8]}
I don't understand how that code can run if it's on it's own just those lines and not work as part of a bigger code
i also tried it with addRequestProperty
Thanks in advance
Instead of setting Content-Length in the request property, use setFixedLengthStreamingMode(postData.length);
According to the source for HttpUrlConnection , Content-Length is a "restricted header":
146 /*
147 * Restrict setting of request headers through the public api
148 * consistent with JavaScript XMLHttpRequest2 with a few
149 * exceptions. Disallowed headers are silently ignored for
150 * backwards compatibility reasons rather than throwing a
151 * SecurityException. For example, some applets set the
152 * Host header since old JREs did not implement HTTP 1.1.
153 * Additionally, any header starting with Sec- is
154 * disallowed.
155 *
156 * The following headers are allowed for historical reasons:
157 *
158 * Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date,
159 * Referer, TE, User-Agent, headers beginning with Proxy-.
160 *
161 * The following headers are allowed in a limited form:
162 *
163 * Connection: close
164 *
165 * See http://www.w3.org/TR/XMLHttpRequest2.
166 */
167 private static final boolean allowRestrictedHeaders;
168 private static final Set<String> restrictedHeaderSet;
169 private static final String[] restrictedHeaders = {
170 /* Restricted by XMLHttpRequest2 */
171 //"Accept-Charset",
172 //"Accept-Encoding",
173 "Access-Control-Request-Headers",
174 "Access-Control-Request-Method",
175 "Connection", /* close is allowed */
176 "Content-Length",
177 //"Cookie",
178 //"Cookie2",
179 "Content-Transfer-Encoding",
180 //"Date",
181 //"Expect",
182 "Host",
183 "Keep-Alive",
184 "Origin",
185 // "Referer",
186 // "TE",
187 "Trailer",
188 "Transfer-Encoding",
189 "Upgrade",
190 //"User-Agent",
191 "Via"
192 };
So, setting Content-Length will be silently ignored.
Authorization is blocked from being returned for security purposes:
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 };
So even if you set the authorization header, you won't get it back when you query the headers.
The content length is set automatically. You can't set it yourself directly. You can however pass the correct length when setting fixed length streaming mode.
来源:https://stackoverflow.com/questions/6564015/httpurlconnection-c-url-openconnection-c-setrequestproperty-doesnt-work