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

发布于 2024-11-18 18:36:31 字数 6795 浏览 3 评论 0原文

这里的代码是一个普通的Java应用程序,而不是Android应用程序,它旨在将C2DM消息发送到具有YOUR_REGISTRATION_STRING的设备,作为具有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 中的哈希图 这是输出:

{Content-Type=[application/x-www-form-urlencoded;charset=UTF-8]}

我不明白如果代码本身只有这些行,它如何运行 并且不能作为更大代码的一部分工作

我也尝试使用 addRequestProperty

提前致谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

別甾虛僞 2024-11-25 18:36:31

不要在请求属性中设置 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<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       };

因此,设置 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       };

因此,即使您设置了授权标头,当您查询标头时也不会取回它。

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.

想挽留 2024-11-25 18:36:31

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

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.

一城柳絮吹成雪 2024-11-25 18:36:31

我遇到了同样的问题,您可以在代码中添加这一行来解决它。

System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

https://stackoverflow.com/a/41841662/15201439

I had the same problem, you can add this line in your code to solve it.

System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

https://stackoverflow.com/a/41841662/15201439

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文