Установите простой заголовок строки (не пару ключ/значение) в HTTP-запросе Volley POST

EDIT: похоже, что основная проблема заключается в установке заголовка, состоящего только из строк, без пар ключ/значение и связанных разделителей, поскольку выполнение ручного запроса curl без =s дало мне ответ сервера, поэтому я отредактировал заголовок.

Я пытаюсь отправить запрос POST для аутентификации, как описано в это руководство по Amazon Alexa из приложения для Android с использованием Volley.

Для второго запроса, который я отправляю (для которого требуется заголовок), я получаю ошибку сервера 400, указывающую на неверный запрос.

Согласно учебной странице, вот как должен выглядеть заголовок запроса:

Запрос должен включать следующие заголовки:

POST /auth/o2/token
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded

Если я использую обычный метод getHeaders() для класса Volley Request для переопределения заголовков, я могу установить только хэш-карту, что приводит к следующему формату заголовка:

{Host=api.amazon.com, Content-Type=application/x-www-form-urlencoded}

(или {POST=/auth/o2/token, Host=api.amazon.com, Content-Type=application/x-www-form-urlencoded}, если я включаю другую строку для первого бита)

Будучи новичком в Volley в целом, я задаюсь вопросом, не упускаю ли я здесь что-то действительно очевидное. Это запрос, который я отправляю:

StringRequest tokenPoller = new StringRequest(
        Request.Method.POST,
        "https://api.amazon.com/auth/O2/token",
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.i("volley", response);
            }
        },
        new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                VolleyLog.d("volley", "Error: " + error.getMessage());
                error.printStackTrace();
            }
        }) {

    @Override
    public String getBodyContentType() {
        return "application/x-www-form-urlencoded";
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        Map<String, String> params = new HashMap<String, String>();
        params.put("grant_type", "device_code");
        params.put("device_code", {{my device code from previous request}});
        params.put("user_code", {{my user code from previous request}});
        return params;
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String>  headers = new HashMap<String, String>();
        headers.put("Host", "api.amazon.com");
        headers.put("Content-Type", "application/x-www-form-urlencoded");

        return headers;
    }
};

Я подозреваю, что что-то с заголовками не так, но я действительно не могу понять это. Я тоже пытался не переопределять заголовки, но безрезультатно. Любые указатели будут высоко оценены! Спасибо!


person Sarah    schedule 29.03.2021    source источник
comment
На данный момент, пробуя ручной запрос на завивание, я почти уверен, что речь идет о форматировании заголовка, который принудительно преобразуется в формат хэш-карты (поэтому я получаю {xxx = xxx}, а не {xxx xxx xx} или {ххх:ххх}.   -  person Sarah    schedule 29.03.2021


Ответы (1)


Ответ 400 в этом случае не означает, что мой запрос был искажен. Это был просто код ответа, который сервер возвращает со всеми ошибками, связанными с процессом авторизации, в моем случае, например. authorization_pending. Поскольку я не запрашивал сообщение об ошибке (через Volley или каким-либо иным образом), я увидел это намного позже.

Хотя в учебнике упоминается, что при опросе токена могут быть доставлены несколько типов ответов, в нем не упоминается, что они на самом деле являются ошибкой и описанием ошибки для ответа 400.

В итоге я переключился с Volley на HttpsUrlConnection и использовал ответы на этот вопрос, чтобы получить сообщение об ошибке и сообщение об ошибке в виде ответа json и реализовать соответствующие реакции.

В итоге мой HTTP-запрос выглядел так:

String stringUrl = "https://api.amazon.com/auth/o2/token";
URL url = null;

try {
    url = new URL(stringUrl);
} catch (MalformedURLException exception) {
    Log.e(TAG, "Error with creating URL", exception);
}

String response = "";
HttpsURLConnection conn = null;
HashMap<String, String> params = new HashMap<String, String>();
String scope_data = null;


try {
    params.put("grant_type", "device_code");
    params.put("device_code", mDeviceCode);
    params.put("user_code", mUserCode);
    Set set = params.entrySet();
    Iterator i = set.iterator();
    StringBuilder postData = new StringBuilder();
    for (Map.Entry<String, String> param : params.entrySet()) {
        if (postData.length() != 0) {
            postData.append('&');
        }
        postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
        postData.append('=');
        postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
    }
    byte[] postDataBytes = postData.toString().getBytes("UTF-8");


    conn = (HttpsURLConnection) url.openConnection();

    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

    conn.setDoOutput(true);
    conn.getOutputStream().write(postDataBytes);

    InputStream inputStream = null;

    try {
        inputStream = conn.getInputStream();
    } catch(IOException exception) {
        inputStream = conn.getErrorStream();
    }

    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    StringBuilder builder = new StringBuilder();

    for (String line = null; (line = reader.readLine()) != null;) {
        builder.append(line).append("\n");
    }

    reader.close();
    conn.disconnect();

    response = builder.toString();
person Sarah    schedule 30.03.2021