Azure Cosmos数据库 - 错误请求 - http:400

时间:2018-04-20 14:12:25

标签: android rest azure retrofit2 azure-cosmosdb

向我的开发人员致意,

已经有3天我正在努力与Cosmos DB连接而没有成功。

我正在使用retrofit作为我的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 Dashboard上显示的数据库数据: db structure

我还尝试为Android找到一些可用的Cosmos DB客户端,以节省时间摆弄身份验证和其余部分。但只能找到这个:https://github.com/Azure/Azure.Android。这正是我正在寻找的,但它仍处于开发阶段,并且缺少MongoDB API(我认为如果它会出现,我会使用MongoDB API来更容易切换)。

非常感谢您的帮助!我对此感到厌倦。

P.S。可以找到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"
}

1 个答案:

答案 0 :(得分:1)

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

您应该将其更改为buildings