Getting (400) Bad Request. when trying to send GCM Message

13,773

Solution 1

I am author of this site which you have referred. Thanks for pointing out the error actually problem is in postData string. We have enclosed our value in double quotes ("like this") but it is a json string so we don't need to do this. Simply remove double quoted around value in postData string and it will work for you.

So just change this

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 + "\"]}";

to this

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 + "\"]}";

and you are done.

I have also corrected it on the post on the link so that other visitors may not face same issue.

Solution 2

I got the same error from sending a GCM Message via HttpWebRequests:

The remote server returned an error: (400) Bad Request.

StatusDescription: InvalidTokenFormat

But the issue wasn't the same. I just had the wrong url:

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

It took me longer than I'd like to admit to figure that out. And I'd like to spare other people the trouble, from such a misleading error message.

Solution 3

Hey asmgx I think I got your problem. I had the same error as well and the typo was in the following line:

Authorization:key=

now I'm not an c# type of guy ;) but it seems like you didn't concatenate "key =" before adding your key, I find that it's easy to have that mistake since I had it as well the first time I was trying GCM.

so make sure you concatenate the "key=" after the "Authorization:", (you probably need the option where the error is unauthorised)

here is the full example from the GCM webpage

Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

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

If that didn't worked and your request seems to be fine to begin with make sure you added your server address to the credentials or just fill it with the fake address given in one of GCM examples on their website (it is something like 0.0.0:0000, couldn't find it ATM so just look for it somewhere in the link I added above or google it).

let me know if both didn't work.

BTW -> think about moving to firebase.

Solution 4

FYI: You will get this code also if your device token to: XXX is wrong or is from the wrong project.

Solution 5

This is how i did it in 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; }

}

Then i use this function to send :

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;
        }
    }
Share:
13,773
asmgx
Author by

asmgx

asmgx

Updated on June 13, 2022

Comments

  • asmgx
    asmgx almost 2 years

    I am trying to send message to GCM Server through C#.net

    I found a good example that I am trying to use

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

    The problem is that I get "The remote server returned an error: (400) Bad Request." error whenever I try to Get the response from this line

                WebResponse wResponse = wRequest.GetResponse();
    

    I tried to find what the prblem is, I changed the API code from Server to Android, to Browser, and the result is either (400) Bad request or (401) Unauthorized.

    Not sure what I am doing wrong here, it looked very simple and straight forward in the example.

    Help is much appreciated

    Here is The code

            NotificationManager nm = new NotificationManager();
            List<string> ls = new List<string>(new string[] { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" });
    
            nm.SendNotification(ls, " Hi.. This is a test","Hi.. Title",1);
    

    and here is the class

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

    Here is how I get the API ID and Sender ID

    Sender ID

    API ID