当尝试发送GCM消息时,出现“获取(400)错误请求”的情况。

4

我正在尝试通过C#.net向GCM服务器发送消息

我找到了一个很好的例子,我正在尝试使用它

http://www.codewithasp.net/2015/11/send-message-gcm-c-sharp-single-multiple.html

每当我尝试从该行获取响应时,就会出现“远程服务器返回错误:(400) 错误请求。”的问题。
            WebResponse wResponse = wRequest.GetResponse();

我试图找出问题所在,我将API代码从服务器更改为Android、浏览器,结果要么是(400)错误请求,要么是(401)未经授权。
不确定我在这里做错了什么,它在示例中看起来非常简单和直接。
非常感谢您的帮助。
以下是代码:
        NotificationManager nm = new NotificationManager();
        List<string> ls = new List<string>(new string[] { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" });

        nm.SendNotification(ls, " Hi.. This is a test","Hi.. Title",1);

这里是类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;
using System.Net;
using System.Text;
using System.IO;

namespace WebApplication1
{

    public class NotificationManager
    {
        private class NotificationMessage
        {
            public string Title;
            public string Message;
            public long ItemId;
        }

        public NotificationManager()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        public string SendNotification(List<string> deviceRegIds, string message, string title, long id)
        {
            try
            {
                string regIds = string.Join("\",\"", deviceRegIds);

                string AppId = "AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
                var SenderId = "1234567890";

                NotificationMessage nm = new NotificationMessage();
                nm.Title = title;
                nm.Message = message;
                nm.ItemId = id;

                var value = new JavaScriptSerializer().Serialize(nm);
                WebRequest wRequest;
                wRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
                wRequest.Method = "post";
                wRequest.ContentType = " application/json;charset=UTF-8";
                wRequest.Headers.Add(string.Format("Authorization: key={0}", AppId));

                wRequest.Headers.Add(string.Format("Sender: id={0}", SenderId));

                string postData = "{\"collapse_key\":\"score_update\",\"time_to_live\":108,\"delay_while_idle\":true,\"data\": { \"message\" : " + "\"" + value + "\",\"time\": " + "\"" + System.DateTime.Now.ToString() + "\"},\"registration_ids\":[\"" + regIds + "\"]}";

                Byte[] bytes = Encoding.UTF8.GetBytes(postData);
                wRequest.ContentLength = bytes.Length;

                Stream stream = wRequest.GetRequestStream();
                stream.Write(bytes, 0, bytes.Length);
                stream.Close();

                WebResponse wResponse = wRequest.GetResponse();

                stream = wResponse.GetResponseStream();

                StreamReader reader = new StreamReader(stream);

                String response = reader.ReadToEnd();

                HttpWebResponse httpResponse = (HttpWebResponse)wResponse;
                string status = httpResponse.StatusCode.ToString();

                reader.Close();
                stream.Close();
                wResponse.Close();

                if (status == "")
                {
                    return response;
                }
                else
                {
                    return "";
                }
            }
            catch( Exception ex)
            {
                return ex.ToString();
            }
        }
    }
}

这是我获取API ID和发送者ID的方法

Sender ID

API ID


相关:无法解析JSON:http://stackoverflow.com/questions/27545782/http-code-400-returned-while-communication-with-gcm - user6522773
5个回答

3

我通过 HttpWebRequest 发送 Google Cloud Messaging(GCM)消息时遇到了与您相同的错误:

远程服务器返回错误:(400) 错误请求。

状态描述:无效的令牌格式。

但问题并非如此。我只是使用了错误的 URL:

"https://fcm.googleapis.com/fcm/send/" //wrong
"https://fcm.googleapis.com/fcm/send"

我花了比我想象中更长的时间才弄清楚这个问题。我希望能够避免其他人因为这个误导性的错误信息而浪费时间。


2
这是我在C#中的做法:
public class VmFcmNotification
{
    public string body { get; set; }
    public string title { get; set; }
    public string icon { get; set; }
    public string text { get; set; }
    public string sound { get; set; }

}

public class VmFcmMessage
{
    /// <summary>
    /// This parameter specifies the recipient of a message.
    /// The value must be a registration token, notification key, or topic.
    /// Do not set this field when sending to multiple topics.
    /// </summary>
    public string to { get; set; }

    /// <summary>
    /// This parameter identifies a group of messages (e.g., with collapse_key: "Updates Available") that can be collapsed,
    /// so that only the last message gets sent when delivery can be resumed.
    /// This is intended to avoid sending too many of the same messages when the device comes back online or becomes active (see delay_while_idle).
    /// Note that there is no guarantee of the order in which messages get sent.
    /// Note: A maximum of 4 different collapse keys is allowed at any given time.
    /// This means a FCM connection server can simultaneously store 4 different send-to-sync messages per client app.
    /// If you exceed this number, there is no guarantee which 4 collapse keys the FCM connection server will keep.
    /// </summary>
    public string collapse_key { get; set; }

    /// <summary>
    /// This parameter, when set to true, allows developers to test a request without actually sending a message.
    /// The default value is false.
    /// </summary>
    public Boolean dry_run { get; set; }

    /// <summary>
    /// This parameter specifies a list of devices (registration tokens, or IDs) receiving a multicast message.
    /// It must contain at least 1 and at most 1000 registration tokens.
    /// Use this parameter only for multicast messaging, not for single recipients.
    /// Multicast messages (sending to more than 1 registration tokens) are allowed using HTTP JSON format only.
    /// </summary>
    public List<string> registration_ids { get; set; }


    public VmFcmNotification notification { get; set; }

}

然后我使用这个函数发送:
public static Boolean SendToOneUser(String userToken, String msgTitle)
    {
        using (var client = new HttpClient())
        {
            var message = new VmFcmMessage();
            message.to = userToken;
            message.notification = new VmFcmNotification()
            {
                title = msgTitle,
                //body = desc,
                //text = desc
            };

            string postBody = JsonConvert.SerializeObject(message).ToString();

            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var SERVER_KEY="key=AIza...........";
            client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", SERVER_KEY);

            var response = client.PostAsync("https://fcm.googleapis.com/fcm/send", new StringContent(postBody, Encoding.UTF8, "application/json"));
            var responseString = response.Result.Content.ReadAsStringAsync().Result;
            //TODO get response and handle send messages
            return true;
        }
    }

什么是 FcmConstants?server_ID 是 API Key 吗? - asmgx
1
是的,请使用您的服务器密钥而不是它。我已经编辑了我的答案。@asmgx - Omid Heshmatinia

1

提示:如果您的设备令牌 to: XXX 错误或来自错误的项目,您也会收到此代码。


1
嘿,asmgx,我想我明白了你的问题。 我也遇到了同样的错误,而错别字在以下行中:

Authorization:key=

现在我不是一个C#类型的人 ;),但似乎你没有在添加密钥之前连接"key =",我发现这很容易出错,因为我第一次尝试GCM时也犯了这个错误。
所以请确保在"Authorization:"后连接"key=",(您可能需要未经授权的选项)。
这是来自 GCM网页的完整示例。
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

{
  "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
  "data" : {
    ...
  },
}

如果这没有起作用,而你的请求似乎一开始就是正确的,请确保将服务器地址添加到凭据中,或者只需使用GCM网站上的一个示例中提供的虚假地址进行填充(它类似于0.0.0:0000,在我找不到它的情况下,请在上面添加的链接中或在Google中查找它)。
如果两者都没有起作用,请让我知道。
顺便说一句->考虑迁移到Firebase。

1
我是您所提到的这个网站的作者。感谢您指出错误,实际上问题在于postData字符串。我们在双引号中("像这样")包含了我们的值,但它是一个json字符串,所以我们不需要这样做。只需删除postData字符串中值周围的双引号即可使其正常工作。

所以只需要更改这个:

string postData = "{\"collapse_key\":\"score_update\",\"time_to_live\":108,\"delay_while_idle\":true,\"data\": { \"message\" : " + "\"" + value + "\",\"time\": " + "\"" + System.DateTime.Now.ToString() + "\"},\"registration_ids\":[\"" + regIds + "\"]}";

到这个

string postData = "{\"collapse_key\":\"score_update\",\"time_to_live\":108,\"delay_while_idle\":true,\"data\": { \"message\" : " + value + ",\"time\": " + "\"" + System.DateTime.Now.ToString() + "\"},\"registration_ids\":[\"" + regIds + "\"]}";

你已经完成了。

我还在链接上的帖子上进行了更正,以便其他访客不会遇到同样的问题。


它正在工作 :) 非常感谢..我可以建议您使用API密钥而不是AppID,并且只是在开头给出每个示例,因为一开始我以为你的意思是“myapp.package.com”之类的。密钥的示例将有助于新手 :) 再次感谢。 - asmgx
我想问一下最后一步“GCM将消息传递给与注册ID相关的设备”,这是由GCM服务器自动完成的吗?是否有任何代码或示例可以说明如何完成此步骤?如果您能在这里帮助我,我将不胜感激。 - asmgx
1
不用谢。我想我已经在使用APIKey而不是AppID了。也许在旧代码中(当您遇到400错误时)我使用了AppID。关于GCM消息传递的工作原理,您可以参考这篇文章http://www.codewithasp.net/2015/11/understanding-mobile-notification-google-cloud-messaging-gcm.html,当然您现在知道如何为gcm注册ID注册设备,我还有一篇文章可以阅读,您可以在这里阅读http://www.codewithasp.net/2015/11/generate-gcm-registration-id-android-application-notification.html。 - Nikhil Gaur
关于最后一部分,我不知道为什么我们需要文本视图和进度条?我以为当应用程序未打开时,消息会显示在移动设备顶部的通知栏中,就像WhatsApp收到消息时一样,你会在通知栏中收到通知。你能解释一下吗?还有其他可以用于最后一步的示例吗?谢谢。 - asmgx
1
是的,你说得对。它会像WhatsApp一样在通知区域显示,即使应用程序没有运行。我已经使用这个文本视图在活动中显示完整的通知文本,当我们点击通知时会打开该活动。就像我们点击WhatsApp通知时,它会带我们进入消息活动界面。 - Nikhil Gaur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接