【问题标题】:Azure Cosmos DB - bad request - http:400Azure Cosmos DB - 错误请求 - http:400
【发布时间】:2018-04-20 14:12:25
【问题描述】:

问候我的开发人员,

我已经 3 天没有成功连接到 Cosmos DB 了。

我使用改造作为我的 REST 客户端和 GsonConverterFactory 用于序列化/反序列化。

当前状态是我从 Cosmos DB REST API 获得 HTTP:400(错误请求)。我尝试采用来自this SO answer 的身份验证标头生成

这是我的代码(此单元测试可在您的开发环境中运行。请参阅本文底部的gradle.build 行来运行它):

@RunWith(AndroidJUnit4.class)
@MediumTest
public class AzureDbConnectionTests {
    public static final int COSMOS_PORT_NUM = 443;
    public static final String COSMOS_DB_URL = "https://mazedb.documents.azure.com";
    public static final String CONNECTION_STR = 
            COSMOS_DB_URL + ":" + COSMOS_PORT_NUM;
    public static final String PRIMARY_KEY = 
"<Private Key>";

    // Entity to serialize into Cosmos DB
    public static class Building {
        public Building() {}

        private String mName;
        private String mAddress;
        private String id;
    }

    public interface FirstAzureService {
        @POST("/dbs/mazedb/colls/buildings/docs")
        Call<Building> addDocument(
            @Header("authorization") String authorization, 
            @Header("x-ms-date") String date, 
            @Body Building building);
    }

    @Test
    public void serverConnectionTest() throws Exception {
        String headerDate = getDateString();

        Building building = new Building();
        building.mName = "UUID";
        building.id = UUID.randomUUID().toString();

        Retrofit retrofit = new Retrofit.Builder().baseUrl(CONNECTION_STR)
            .addConverterFactory(GsonConverterFactory.create()).build();

        FirstAzureService azureService = retrofit.create(FirstAzureService.class);

        Call<Building> buildingCall = azureService.addDocument(
            generateAuthHeader("post", "docs", "dbs/mazedb/colls/buildings",
            headerDate, PRIMARY_KEY), headerDate, building);

        Response<Building> response = buildingCall.execute();
        Log.d("AzureDbConnectionTest", "HTTP status code: " + response.code());
        Log.d("AzureDbConnectionTest", "HTTP message: " + response.message());
        Log.d("AzureDbConnectionTest", headerDate);
        assertTrue(response.isSuccessful());
    }

    private String generateAuthHeader(String verb, String resourceType, String resourceId, String headerDate, String masterKeyBase64) throws Exception
    {
        //Decode the master key, and setup the MAC object for signing.
        byte[] masterKeyBytes = Base64.decode(PRIMARY_KEY, Base64.NO_WRAP);
        Mac mac = Mac.getInstance("HMACSHA256");
        mac.init(new SecretKeySpec(masterKeyBytes, "HMACSHA256"));

        //Build the unsigned auth string.
        String stringToSign = verb.toLowerCase() + "\n"
                + resourceType.toLowerCase() + "\n"
                + resourceId.toLowerCase() + "\n"
                + headerDate.toLowerCase() + "\n"
                + "\n";

        //Sign and encode the auth string.
        String signature = Base64.encodeToString(
            mac.doFinal(stringToSign.toLowerCase().getBytes("UTF8")), Base64.NO_WRAP);

        //Generate the auth header.
        String authHeader = 
            URLEncoder.encode("type=master&ver=1.0&sig=" + signature, "UTF8");

        return authHeader;
    }

    @NonNull
    public static String getDateString() {
        SimpleDateFormat formatter = 
            new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
        formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
        return formatter.format(new Date()).toLowerCase();
    }
}

API 是 SQL API。 Azure 仪表板上显示的数据库数据: db structure

我还尝试为 android 找到一些可用的 Cosmos DB 客户端,以节省处理身份验证和其他操作的时间。但只能找到这个:https://github.com/Azure/Azure.Android。这正是我正在寻找的,但它仍在开发中并且缺少 MongoDB API(我想使用 MongoDB API 来更容易地切换,如果它来了)。

非常感谢您的帮助!我已经厌倦了。

附: Azure Cosmos DB 的 HTTP 状态代码列表可以在 on official website 找到。从那里代码400的原因是:

  • 请求正文中的 JSON、SQL 或 JavaScript 无效。
  • 此外,当资源的所需属性不存在或未在资源的 POST 或 PUT 正文中设置时,也可以返回 400。
  • 当 GET 操作的一致性级别被帐户的一组更强的一致性覆盖时,也会返回 400。
  • 当需要 x-ms-documentdb-partitionkey 的请求不包含它时,也会返回 400。

我认为最有可能是错误的 JSON,但在另一个单元测试中对同一对象进行序列化后,我发现它没问题: {"id":"cceb3f5d-8d9c-44cd-85ee-599cd2f58783","mName":"UUID"}

最诚挚的问候,格雷格。

build.gradle 运行它:

dependencies {
    androidTestCompile "junit:junit:4.12"
    androidTestCompile "com.android.support:support-annotations:25.3.1"
    androidTestCompile "com.android.support.test:runner:0.5"
    androidTestCompile "com.android.support.test:rules:0.5"
    androidTestCompile "com.google.code.gson:gson:2.8.2"
    androidTestCompile "com.squareup.retrofit2:retrofit:2.4.0"
    androidTestCompile "com.squareup.retrofit2:converter-gson:2.4.0"
}

【问题讨论】:

  • 您必须立即更改您的帐户密钥!
  • @GauravMantri 我编辑了它,但我认为他拒绝了编辑
  • 我可能会错过编辑。这些键并不重要。 DB 仅用于启动项目。当然,我稍后会更改密钥。谢谢。
  • @GregoryStein 人们可以更改报价并开始向您发送垃圾邮件以向您收费。
  • @Elfocrash 仅供参考,即使您编辑了某人的密钥(应该这样做),任何有足够代表的人都可以阅读编辑历史并查看密钥,这就是为什么在意外发布合法时更改密钥至关重要的原因, 当前键。

标签: android rest azure retrofit2 azure-cosmosdb


【解决方案1】:

generateAuthHeader 方法中,您提供dbs/mazedb/colls/buildings 作为String resourceId,这是集合ID。 这是错误的。

你应该把它改成buildings

【讨论】:

  • 感谢您的回答。我试图将“dbs/mazedb/colls/buildings”更改为“buildings”但无济于事 - 相同的 400 HTTP 响应。 (我在网上某处看到应该和我写的一样——但不知道是不是真的)
猜你喜欢
  • 2017-07-21
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多