FCM授权总是失败

FCM Authorization always fails

今天我想从 GCM 切换到 FCM,所以我设置了所需的一切并希望实现服务器端代码。我使用了 gcm4j 库并将其更改为地址为 https://fcm.googleapis.com/fcm/send

所以我正在做以下事情:

FCM fcm = new FCMDefault(new FCMConfig().withKey(FCMGlobals.FCM_API_KEY));

FCMRequest request = new FCMRequest().withRegistrationId(android.getRegistration())
    // .withCollapseKey(collapseKey)
    .withDelayWhileIdle(true)
    .withDataItem(FCMGlobals.FCM_PARAM_CODE, code)
    .withDataItem(FCMGlobals.FCM_PARAM_USER_ID, "" + user.getId())
    .withDataItem(FCMGlobals.FCM_PARAM_ADDITION, "" + addition);

ListenableFuture<FCMResponse> responseFuture = fcm.send(request);

Futures.addCallback(responseFuture, new FutureCallback<FCMResponse>() {

    public void onFailure(Throwable t) {
        log.error(t);
    }

    @Override
    public void onSuccess(FCMResponse response) {
        log.info(response.toString());
    }
});

其实现是:

protected FCMResponse executeRequest(FCMRequest request) throws IOException {
    byte[] content = this.objectMapper.writeValueAsBytes(request);

    HttpURLConnection conn = this.connectionFactory.open(this.fcmUrl);
    conn.setRequestMethod("POST");
    conn.addRequestProperty("Authorization", getAuthorization(request));
    conn.addRequestProperty("Content-Type", "application/json");
    conn.setDoOutput(true);
    conn.setFixedLengthStreamingMode(content.length);

    LoggerFactory.getLogger("FCMDefaultAbstract").info("Authorization: " + conn.getRequestProperty("Authorization"));
    LoggerFactory.getLogger("FCMDefaultAbstract").info("Content-Type: " + conn.getRequestProperty("Content-Type"));
    LoggerFactory.getLogger("FCMDefaultAbstract").info("send: " + new String(content));

    try (OutputStream outputStream = conn.getOutputStream()) {
        IOUtils.write(content, outputStream);
    } catch (Exception e) {
        throw new FCMNetworkException("Error sending HTTP request to FCM", e);
    }

    FCMResponse response;

    try (InputStream inputStream = conn.getInputStream()) {
        response = this.objectMapper.readValue(IOUtils.toByteArray(inputStream), FCMResponse.class);
    } catch (IOException e) {
        try (InputStream inputStreamError = conn.getErrorStream()) {
            String str = inputStreamError != null ? IOUtils.toString(inputStreamError) : "No error details provided";
            int responseCode = conn.getResponseCode();

            if (responseCode < 500) {
                throw new FCMNetworkException(conn.getResponseCode(), str.trim(), e);
            } else {
                throw new FCMNetworkException(conn.getResponseCode(), str.trim(), checkForRetryInResponse(conn), e);
            }
        }
    }

    response.setRequest(request);
    response.setRetryAfter(checkForRetryInResponse(conn));

    Iterator<String> iteratorId = request.getRegistrationIds().iterator();
    Iterator<FCMResult> iteratorResponse = response.getResults().iterator();

    while (iteratorId.hasNext() && iteratorResponse.hasNext()) {
        iteratorResponse.next().setRequestedRegistrationId(iteratorId.next());
    }

    if (iteratorId.hasNext()) {
        LOG.warn("Protocol error: Less results than requested registation IDs");
    }

    if (iteratorResponse.hasNext()) {
        LOG.warn("Protocol error: More results than requested registation IDs");
    }

    return response;
}

这里是日志输出:

FCMDefaultAbstract                      Authorization: null
FCMDefaultAbstract                      Content-Type:application/json
FCMDefaultAbstract                      send: {"registration_ids":["dMpvzp*************************************2lRsSl_5lFET2"],"data":{"CODE":"201","USER_ID":"1","ADDITION":"1468083549493"},"delay_while_idle":true}
FCM                                     FCMNetworkException: HTTP 401: No error details provided

Authorization header 实际上不为空。它已使用我的 FCM API 密钥正确设置。如果有人试图访问 Authorization 密钥,只有 HTTPUrlConnection 实现会说 return null。

如您所见,我无法连接 FCM。代码 401 表示身份验证失败。

这可能是什么问题?

检查您使用的是 server type API-KEY,而不是 clientbrowser API-KEY。

如果您使用的是 Firebase,您可以在
中找到 API-KEY 项目设置 > 云消息

如果您正在使用云控制台,或者您不确定您使用的是哪个密钥, 您可以通过 https://console.cloud.google.com

生成新密钥

引用文档
https://firebase.google.com/docs/cloud-messaging/concept-options#credentials

Server key: A server key that authorizes your app server for access to Google services, including sending messages via Firebase Cloud Messaging. [...]
Important: Do not include the server key anywhere in your client code. Also, make sure to use only server keys to authorize your app server. Android, iOS, and browser keys are rejected by FCM.