HttpURLConnection c = URL.openConnection(); c.setRequestProperty()不起作用

这里的代码是一个普通的Java应用程序而不是android应用程序,它设计用于将带有YOUR_REGISTRATION_STRING的C2DM消息作为开发人员用auth_key发送到该设备,问题描述如下

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 = [应用/ X WWW的窗体-urlencoded;字符集= UTF-8]}

我不明白代码是如何运行的,如果它只是那些行而不是作为更大的代码的一部分工作

我也尝试使用addRequestProperty

提前致谢

不要在request属性中设置Content-Length,而是使用setFixedLengthStreamingMode(postData.length);

根据HttpUrlConnection的源代码 ,Content-Length是一个“受限标题”:

 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 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 }; 

因此,设置Content-Length将被默默忽略。

出于安全目的,阻止授权被拒绝:

 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 }; 

因此,即使您设置了授权标头,在查询标头时也不会将其恢复。

内容长度自动设置。 您无法直接自行设置。 但是,在设置固定长度流模式时,您可以传递正确的长度。

Interesting Posts