Ошибка сервера iris callback api неправильный формат ответа нужен json

Есть простой бот на vk_api. Я хочу подключить его к Callback API в группе ВК через Flask. Использую хост Pythonanywere (создаю приложение). При запуске самого кода (через консоль) происходит ошибка RuntimeError: Working outside of request context. При попытке подключения к Callback API приложение просто возвращает стандартный текст. Как избавится от ошибки?

from flask import Flask, request, json
import vk_api
import vk
from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType
from vk_api.utils import get_random_id
import requests

vk_session = vk_api.VkApi(token='токен')
longpoll = VkBotLongPoll(vk_session, ID_группы)
vk = vk_session.get_api()
app = Flask(__name__)

@app.route('/', methods = ["POST"])

def main():
    data = json.loads(request.data)
    if data['type'] == 'confirmation':
        return 'код подтверждения'
    elif data['type'] == 'message_new':
        for event in longpoll.listen():
            if event.type == VkBotEventType.MESSAGE_NEW:
                if event.obj.text == '!Привет':
                    if event.from_user:
                        vk.messages.send(
                            user_id=event.user_id,
                            random_id=get_random_id(),
                            message='Привет'
                        )
                    elif event.from_chat:
                        return 'ok'
if __name__ == '__main__':
    main()

ошибка в консоли
ошибка в вк

0 / 0 / 1

Регистрация: 15.02.2017

Сообщений: 93

1

25.03.2018, 17:10. Показов 2902. Ответов 3


Не могу понять как отправить ответ
Вот что нужно


Для получения уведомлений нужно подтвердить адрес сервера. На него будет отправлен POST-запрос, содержащий JSON:
{ «type»: «confirmation», «group_id»: 147772829 }
Строка, которую должен вернуть сервер: 85b38f4f

подскажите как вернуть строку на php чет не могу понять

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь

0

Dmitry

Эксперт по компьютерным сетямЭксперт NIX

12380 / 7220 / 757

Регистрация: 09.09.2009

Сообщений: 28,177

25.03.2018, 17:13

2

PHP
1
echo json_encode(array('param1'=>'value1','param2'=>'value2'));

0

TopusT

0 / 0 / 1

Регистрация: 15.02.2017

Сообщений: 93

25.03.2018, 17:42

 [ТС]

3

Dmitry, вот что я отправил

PHP
1
echo json_encode(array("85b38f4f"));

Вот что вернуло

PHP
1
Сервер вернул неправильный ответ: ["85b38f4f"]

не знаю как убрать [«»]

0

edward_freedom

1568 / 1447 / 303

Регистрация: 01.10.2011

Сообщений: 2,636

25.03.2018, 19:27

4

Цитата
Сообщение от TopusT
Посмотреть сообщение

Строка, которую должен вернуть сервер: 85b38f4f

PHP
1
echo "85b38f4f";

1

Простейший пример обработки сигналов, получаемых от бота ВК Iris CM.

Настройка базы данных сожедержится в файле «/classes/db.php».

Обратите внимание, что в репозитории находится файл «/classes/db.example.php». Его необходимо переименовать в «/classes/db.php». Это сделано с целью предотвращения случайного стирания файла с актуальными данными.

Классы обработки сигналов находятся в папке «/classes/Ub/Callback/».

Дамп базы данных находится в файле «/db.sql». База данных MySQL. Требуется модуль curl и mysqli

Перечень сигналов, обрабатываемых сервером:

«ping» — Ub.Callback.Ping — сигнал проверки доступности сервиса и наличия пользователя с данными id пользователя/секретная фраза

«banExpired» — Ub.Callback.AddUser — сигнал истечения срока бана

«addUser» — Ub.Callback.AddUser — сигнал необходимости добавить пользователя

«bindChat» — Ub.Callback.Bind — сигнал инициализации беседы

«subscribeSignals» — Ub.Callback.Bind — сигнал о подписке на события в беседе

«deleteMessages» — Ub.Callback.DeleteMessages — сигнал о необходимости удалить сообщения

«printBookmark» — Ub.Callback.PrintBookmark — сигнал о необходимости показать сообщение из истории

Подробное описание структуры сигналов в статье https://vk.com/@iris_live-api2

I had this issue, which originated from an invalid handler code which looks completely fine:

exports.handler = (event, context) => {
    return {
       isBase64Encoded: false,
       body: JSON.stringify({ foo: "bar" }),
       headers: {
          'Access-Control-Allow-Origin': '*',
       },
       statusCode: 200,
    };
}

I got the hint from examining the somewhat confusing API Gateway response logs:

> Endpoint response body before transformations: null

The way to fix it would be to either

  • Add the async keyword (async function implicitly returns a Promise):
exports.handler = async (event, context) => {
    return {
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    };
}
  • Return a Promise:
exports.handler = (event, context) => {
    return new Promise((resolve) => resolve({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    }));
}
  • Use the callback:
exports.handler = (event, context, callback) => {
    callback({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    });
}

My handler was previously declared async without ever using await, so I removed the async keyword to reduce complexity of the code, without realizing that Lambda expects either using async/await/Promise or callback return method.

I had this issue, which originated from an invalid handler code which looks completely fine:

exports.handler = (event, context) => {
    return {
       isBase64Encoded: false,
       body: JSON.stringify({ foo: "bar" }),
       headers: {
          'Access-Control-Allow-Origin': '*',
       },
       statusCode: 200,
    };
}

I got the hint from examining the somewhat confusing API Gateway response logs:

> Endpoint response body before transformations: null

The way to fix it would be to either

  • Add the async keyword (async function implicitly returns a Promise):
exports.handler = async (event, context) => {
    return {
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    };
}
  • Return a Promise:
exports.handler = (event, context) => {
    return new Promise((resolve) => resolve({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    }));
}
  • Use the callback:
exports.handler = (event, context, callback) => {
    callback({
        isBase64Encoded: false,
        body: JSON.stringify({ foo: "bar" }),
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
        statusCode: 200,
    });
}

My handler was previously declared async without ever using await, so I removed the async keyword to reduce complexity of the code, without realizing that Lambda expects either using async/await/Promise or callback return method.

Ошибка обновления. Ответ не является допустимым ответом JSON

Обновление не удалось. Ответ не является допустимым ответом JSON. Как оказалось, с такой ошибкой сталкиваются многие вебмастеры при обновлении или публикации записей в WordPress.

С ней же столкнулся и я при переносе сайта своего клиента с хостинга Beget на Namecheap. Кстати, консоль у меня была на английском языке, и эта ошибка звучала так: Updating failed. The response is not a valid JSON response.

В этом материале я расскажу о всех возможных способах решить эту проблему, и какой помог лично мне.

Навигация по статье

Почему возникает эта ошибка?

Причин возникновения этой ошибки множество, но самая распространенная — отключение событий REST API. Но мы не будем останавливаться только на ней и рассмотрим все возможные способы решения этой проблемы.

Кстати, так выглядит сама ошибка обновления, возникающая при публикации или обновлении записи в WordPress.

Ошибка обновления WordPress

Как я решил эту проблему? Изначально я создавал сайт на хостинге Beget, после завершения работы требовалось выгрузить сайт на хостинг Namecheap. И сразу после публикации сайта я обнаружил, что больше могу обновлять или создавать новые записи/страницы. Особо никаких действий предпринимать мне не хотелось, поэтому я просто написал в техподдержку, и там решили мою проблему.

Если же техподдержка вашего хостинга не очень отзывчивая, то я рекомендую перейти на Beget и обязательно указать мой код партнера 1486766 при регистрации! 😀

А если серьезно, то попробуйте каждый из описанных ниже методов, и один из них вам наверняка поможет!

Способ 1. Обновите постоянные ссылки

Перейдите в консоль вашего сайта, затем в Настройки и найдите там пункт Постоянные ссылки.

Обновление постоянных ссылок

Здесь вам требуется просто нажать на кнопку Обновить. После этого можно проверить изменения.

Способ 2. Установка классического редактора WordPress

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

Плагин Classic Editor WordPress

Скачайте плагин Классический редактор с официального репозитория WordPress. Затем перейдите в НастройкиНаписание. Здесь вам нужно найти параметр Классический редактор для всех пользователей и выбрать значение Для всех.

Можно проверить изменения. Если не помогло, переходим к следующему способу!

Способ 3. Отсутствие SSL сертификата или его некорректная настройка

Зачастую многие регистраторы и хостинг-провайдеры предлагают слишком дорогие SSL-сертификаты, цена на которые порой превышает 5 000 рублей за год. Далеко не все готовы платить столько денег и ищут возможность подключить бесплатный SSL-сертификат.

Зачастую эти попытки заканчиваются неудачами, некорректными настройками сайта, что приводит к ряду ошибок.

Если вы новичок, то крайне рекомендую использовать хостинг Beget в своей работе. Он не только предоставляет бесплатный пробный период на 30 дней для любого тарифа, но и выдает бесплатные рабочие SSL-сертификаты. Я уже как-то писал обзор на хостинг Beget, рекомендую к прочтению!

Способ 4. Устранение ошибки смешанного содержимого

Данное решение поможет, если ошибка возникла после подключения SSL-сертификата. Для начала перейдите в раздел настроек вашего сайта и проверьте, чтобы URL WordPress Address (Адрес WordPress) и URL Site Address (Адрес сайта) начинались с протокола безопасного соединения https.

Адрес WordPress и адрес сайта

Затем перейдите в раздел плагинов, скачайте и установите Really Simple SSL. После активации плагина появится уведомление Almost Ready to migrate SSL. Нажмите на синюю кнопку Activate SSL.

Плагин Really Simple SSL WordPress

Затем идем в Настройки, находим раздел SSL. Проконтролируйте, чтобы первые три пункта (Mixed content fixer, Enable WordPress 301 Redirection to SSL, Enable 301 .htaccess redirect) были активны. По окончанию настройки проверяем изменения.

Способ 5. Проверка тем и плагинов

Если ошибка «Обновление не удалось. Ответ не является допустимым ответом JSON» появилась после установки какой-то темы или плагина, то не сложно догадаться, в чем может быть причина ее возникновения.

Попробуйте переключиться на другую тему и проверить изменения. Затем отключите все плагины и снова проверьте изменения. Если же проблема решена, то остается только выяснить, какой из плагинов вызывает эту ошибку. Включайте их по очереди и проверяйте, появилась ли снова эта проблема.

Способ 6. Удостоверьтесь, что вы не отключили Rest API и wp-json

В самом начале этого материала я сказал, что это одна из самых частых причин возникновения ошибки обновления записей и страниц.

Перейдите в редактор вашей темы и найдите файл functions.php. А теперь внимательно изучите его содержимое. Если проблема кроется в отключении REST API и wp-json вы найдете примерно следующее:

// Отключаем сам REST API
add_filter('rest_enabled', '__return_false');

// Отключаем фильтры REST API
remove_action( 'xmlrpc_rsd_apis',            'rest_output_rsd' );
remove_action( 'wp_head',                    'rest_output_link_wp_head', 10, 0 );
remove_action( 'template_redirect',          'rest_output_link_header', 11, 0 );
remove_action( 'auth_cookie_malformed',      'rest_cookie_collect_status' );
remove_action( 'auth_cookie_expired',        'rest_cookie_collect_status' );
remove_action( 'auth_cookie_bad_username',   'rest_cookie_collect_status' );
remove_action( 'auth_cookie_bad_hash',       'rest_cookie_collect_status' );
remove_action( 'auth_cookie_valid',          'rest_cookie_collect_status' );
remove_filter( 'rest_authentication_errors', 'rest_cookie_check_errors', 100 );

// Отключаем события REST API
remove_action( 'init',          'rest_api_init' );
remove_action( 'rest_api_init', 'rest_api_default_filters', 10, 1 );
remove_action( 'parse_request', 'rest_api_loaded' );

// Отключаем Embeds связанные с REST API
remove_action( 'rest_api_init',          'wp_oembed_register_route'              );
remove_filter( 'rest_pre_serve_request', '_oembed_rest_pre_serve_request', 10, 4 );
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
// Отключаем wp-json
add_filter('rest_enabled', '__return_false');
remove_action( 'xmlrpc_rsd_apis', 'rest_output_rsd' );
remove_action( 'wp_head', 'rest_output_link_wp_head', 10, 0 );
remove_action( 'template_redirect', 'rest_output_link_header', 11, 0 );
remove_action( 'auth_cookie_malformed', 'rest_cookie_collect_status' );
remove_action( 'auth_cookie_expired', 'rest_cookie_collect_status' );
remove_action( 'auth_cookie_bad_username', 'rest_cookie_collect_status' );
remove_action( 'auth_cookie_bad_hash', 'rest_cookie_collect_status' );
remove_action( 'auth_cookie_valid', 'rest_cookie_collect_status' );
remove_filter( 'rest_authentication_errors', 'rest_cookie_check_errors', 100 );
remove_action( 'init', 'rest_api_init' );
remove_action( 'rest_api_init', 'rest_api_default_filters', 10, 1 );
remove_action( 'parse_request', 'rest_api_loaded' );
remove_action( 'rest_api_init', 'wp_oembed_register_route' );
remove_filter( 'rest_pre_serve_request', '_oembed_rest_pre_serve_request', 10, 4 );
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_add_host_js' );

Если у вас есть похожий код, то удаляем его. Затем переходим в Настройки, находим раздел «Постоянные ссылки» и нажимаем «обновить».

Способ 7. Узнать ответ у техподдержки вашего хостинга

Иногда проблема может возникнуть не из-за вашего сайта, а некорректных настроек сервера. Попробуйте обратиться в техподдержку вашего хостинга с просьбой решить вашу проблему.

Кстати, а вам рассказать, у какого хостинга самая лучшая техподдержка? 😀 Конечно же у Beget! А вы думали, я какой-то другой хостинг здесь посоветую? (Не забывайте при регистрации указывать мой партнерский код 1486766, так я заработаю много денег и больше не буду писать статьи).

Вам понравился материал? Интересует разработка сайтов? Тогда обязательно подпишитесь на нашу группу ВКонтакте! Так вы всегда будете в курсе событий и никогда не пропустите новые материалы. А еще у нас есть беседа с активными участниками, где мы бесплатно помогаем новичкам с решением любых вопросов! 🙂

У меня есть метод в моем приложении REST, который возвращает ответ. Я использую определенный класс RestResponse для персонализации своего ответа, затем я использую throw200Ok, чтобы вернуть ответ:

@GET
@Path("/resultat/{id}")
public Response getResultat(@PathParam("id") int id) {
    Response response = null;
    RestResponse<JsonObject> restResponse = new RestResponse<JsonObject>();
    JsonObject jsonObject = null;

    "Some code"

    jsonObject = SMConverter.getResultat(socialChoices, list);
    restResponse.setData(jsonObject);
    response = restResponse.throw200Ok();

    return response;
}

Класс SMConverter:

public class SMConverter {

private static String RESULTATS = "resultats";
private static String STATS = "stats";

/**
 * Transform a SocialChoices and a list of vote which belong to him to a JsonObject which contain
 * the result and statistics
 * @param socialChoices
 * @param list
 * @return JsonObject
 */
public static JsonObject getResultat(SocialChoices socialChoices, List<Votes> list) {

    // Recover the number of choice
    int nbChoice = socialChoices.getValue().size();
    // Recover the number of voter
    int nbVoter = list.size();

    try {
        Matrix matrix = new Matrix(nbVoter, nbChoice);
        matrix.init();

        // Maps used to treat the response to clear informations
        HashMap<String, Integer> map = new HashMap<>();
        HashMap<Integer, String> mapReverse = new HashMap<>();

        for(int i = 0; i < nbChoice; i++) {
            // Map the i index to the choice i and put it in a HashMap
            String valueChoice = socialChoices.getValue().get(i).getName();
            map.put(valueChoice,i);
            mapReverse.put(i,valueChoice);
        }

        System.out.println(map);
        System.out.println(mapReverse);

        int choiceNb = socialChoices.getData().getInt("choiceNb");
        boolean ordered = socialChoices.getData().getBoolean("ordered");
        System.out.println(choiceNb);
        System.out.println(ordered);

        if (choiceNb > 1 && ordered) {
            for (int x = 0; x < nbVoter; x ++) {
                for (int j = choiceNb; j > 0; j--) {
                    // Recover the choice of each voter
                    String choice = list.get(x).getData().getString(Integer.toString(choiceNb-j+1));
                    // Use the map to get the index of the voter choice and map it to a tab
                    // Tab could be seen as a Matrix representing the choice of each voter
                    matrix.getTab()[map.get(choice)][x] = (byte) j;
                }
            }
            System.out.println(matrix);
            JsonObject jsonObject = treatment(ScrutinMajoritaireParSomme.voteScrutinMajoritaireParSomme(matrix),  mapReverse);
            System.out.println(jsonObject);

            return jsonObject;
        } else if ( !ordered ) {
            System.out.println("ok ok");
            for (int x = 0; x < nbVoter; x ++) {
                for (int j = choiceNb; j > 0; j--) {
                    // Recover the choice of each voter
                    // choiceNb-j+1 : because j start at choiceNb and not 1
                    String choice = list.get(x).getData().getString(Integer.toString(choiceNb-j+1));
                    // Use the map to get the index of the voter choice and map it to a tab
                    // Tab could be seen as a Matrix representing the choice of each voter
                    matrix.getTab()[map.get(choice)][x] = 1;
                }
            }
            System.out.println(matrix);
            JsonObject jsonObject = treatment(ScrutinMajoritaireParSomme.voteScrutinMajoritaireParSomme(matrix),  mapReverse);
            System.out.println(jsonObject);

            return jsonObject;
        }

    } catch (MatrixFormatException e) {
        e.printStackTrace();
    }

    return null;
}

/**
 * Transform a result to a clear and readable JsonObject
 * @param resu
 * @param map
 * @return
 */
public static JsonObject treatment(Resultat resu, HashMap<Integer, String> map) {

    JsonObjectBuilder resultats = Json.createObjectBuilder();
    JsonObjectBuilder stats = Json.createObjectBuilder();

    // For each result set the ranking and the choice to a readable name
    for (int i = 0; i < resu.getResultats().size(); i++) {
        resultats.add(Integer.toString(i+1),map.get(resu.getResultats().get(i+1)));
    }

    // For each statistics transform the key index to a readable name
    for (int j = 0; j < resu.getStats().size(); j++) {
        stats.add(map.get(j),resu.getStats().get(j));
    }

    JsonObject value = Json.createObjectBuilder()
            .add(RESULTATS,resultats.build())
            .add(STATS,stats.build())
            .build();

    return value;
}
}

Моя переменная jsonObject соответствует:

{"resultats":{"1":"a"},"stats":{"a":3,"b":1,"c":0}}

Мой класс RestResponse для персонализации моего ответа. Метод throw200Ok (), который я использую, возвращает ответ:

public class RestResponse<T> implements Serializable {
private int httpErrorCode;
private T data;
private String errorMessage;
public static final String MEDIA_TYPE = MediaType.APPLICATION_JSON + ";charset=utf-8";


public RestResponse(){
    httpErrorCode = 200;
}

/**
 * Constructor by parameter
 * @param httpErrorCode
 * @param data
 * @param errorMessage
 */
public RestResponse(int httpErrorCode, T data, String errorMessage) {
    this.httpErrorCode = httpErrorCode;
    this.data = data;
    this.errorMessage = errorMessage;
}

public Response throw200Ok() {
    setHttpErrorCode(200);
    return Response.ok(this).type(MEDIA_TYPE).build();
}

public Response throw204NoContent(){
    setHttpErrorCode(204);
    return Response.status(Response.Status.NO_CONTENT).entity(this).type(MEDIA_TYPE).build();
}

public Response throw403Forbidden() {
    setHttpErrorCode(403);
    return Response.status(Response.Status.FORBIDDEN).entity(this).type(MEDIA_TYPE).build();
}

public Response throw404NotFound(){
    setHttpErrorCode(404);
    return Response.status(Response.Status.NOT_FOUND).entity(this).type(MEDIA_TYPE).build();
}

public Response throw405MethodNotAllowed() {
    setHttpErrorCode(405);
    return Response.status(405).entity(this).type(MEDIA_TYPE).build();
}

public Response throw409Conflict() {
    setHttpErrorCode(409);
    return Response.status(Response.Status.CONFLICT).entity(this).type(MEDIA_TYPE).build();
}

public Response throw412PreconditionFailed() {
    setHttpErrorCode(412);
    return Response.status(Response.Status.PRECONDITION_FAILED).entity(this).type(MEDIA_TYPE).build();
}

public Response throw500InternalServerError() {
    setHttpErrorCode(500);
    return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(this).type(MEDIA_TYPE).build();
}

public int getHttpErrorCode() {
    return httpErrorCode;
}

/**
 *
 * @param httpErrorCode
 */
private void setHttpErrorCode(int httpErrorCode) {
    this.httpErrorCode = httpErrorCode;
}

public boolean isSuccess() {
    return httpErrorCode == 200;
}

public T getData() {
    return data;
}

/**
 *
 * @param data
 */
public void setData(T data) {
    this.data = data;
}

public String getErrorMessage() {
    return errorMessage;
}

/**
 *
 * @param errorMessage
 */
public void setErrorMessage(String errorMessage) {
    this.errorMessage = errorMessage;
}
}

Затем я возвращаю «Ответ» из моего приложения REST. И я делаю запрос с правильным URL, и мой ответ:

{
"httpErrorCode": 200,
"data": {
  "resultats": {
    "1": {
      "chars": "a",
      "valueType": "STRING",
      "string": "a"
    }
  },
  "stats": {
    "a": {
      "integral": true,
      "valueType": "NUMBER"
    },
    "b": {
      "integral": true,
      "valueType": "NUMBER"
    },
    "c": {
      "integral": true,
      "valueType": "NUMBER"
    }
  }
},
"errorMessage": null,
"success": true
}

Вместо того :

{
"httpErrorCode": 200,
"data": {
  "resultats":{"1":"a"},
  "stats":{"a":3,"b":1,"c":0}
},
"errorMessage": null,
"success": true
}

3 ответа

Лучший ответ

Я нашел решение.

Вместо передачи «this» во всех моих методах RestResponse я передаю «this.toString». Кроме того, у меня есть метод «@Override» toString для управления отображением моего ответа.

return Response.status(Response.Status.ACCEPTED).entity(this.toString()).type(MEDIA_TYPE).build();

Моя переопределение:

@Override
public String toString() {
    final StringBuilder sb = new StringBuilder("{");
    sb.append(""httpErrorCode":").append(httpErrorCode);
    sb.append(", "data":").append(data.toString());
    sb.append(", "errorMessage":").append(errorMessage);
    sb.append('}');
    return sb.toString();
}


0

Pierre Rol
24 Май 2017 в 08:09

"a": {
      "integral": true,
      "valueType": "NUMBER"
    },

В построителе ответов вместо передачи значения вы передаете тип данных этого значения. Пожалуйста, проверьте логику построения ответа.


0

kswaughs
23 Май 2017 в 15:09

Этот прием должен сработать: в самом конце, перед передачей объекта json в Response, просто зафиксируйте его: jsonObject => jsonObject.toString()

Кроме того, я бы порекомендовал вам всегда использовать правильный тип контента: @Produces(APPLICATION_JSON)

В вашем случае код должен выглядеть так:

@GET
@Path("/resultat/{id}")
@Produces(APPLICATION_JSON) // 2) optional
public Response getResultat(@PathParam("id") int id) {
    Response response = null;
    RestResponse<JsonObject> restResponse = new RestResponse<JsonObject>();
    JsonObject jsonObject = null;

    "Some code"

    jsonObject = SMConverter.getResultat(socialChoices, list);
    restResponse.setData(jsonObject.toString()); // 1) .toString() should do a trick!
    response = restResponse.throw200Ok();

    return response;
}


0

Maksim Kostromin
16 Янв 2018 в 22:37


Существуют ли стандарты или лучшие практики для структурирования ответов JSON из API? Очевидно, что данные каждого приложения различны, так что меня это не касается, а скорее «шаблон ответа», если хотите. Пример того, что я имею в виду:

Успешный запрос:

{
  "success": true,
  "payload": {
    /* Application-specific data would go here. */
  }
}

Неудачный запрос:

{
  "success": false,
  "payload": {
    /* Application-specific data would go here. */
  },
  "error": {
    "code": 123,
    "message": "An error occurred!"
  }
}





Ответы:


Да, есть пара стандартов (хотя и с определенными свободами в определении стандарта):

  1. JSON API — JSON API охватывает также создание и обновление ресурсов, а не только ответы.
  2. JSend — Простой и, вероятно, то, что вы уже делаете.
  3. OData JSON Protocol — очень сложный.
  4. HAL — как OData, но стремится быть как HATEOAS .

Есть также форматы описания JSON API:

  • развязность
    • Схема JSON (используется Swagger, но вы можете использовать его отдельно)
  • WADL в JSON
  • RAML
  • HAL, потому что HATEOAS в теории самоописывает себя.






Руководство по Google JSON

Возвращение ответа успеха data

{
  "data": {
    "id": 1001,
    "name": "Wing"
  }
}

Ответ об ошибке возврата error

{
  "error": {
    "code": 404,
    "message": "ID not found"
  }
}

и если ваш клиент JS, вы можете использовать, if ("error" in response) {}чтобы проверить, есть ли ошибка.







Я предполагаю, что стандарт де-факто действительно не появился (и, возможно, никогда). Но независимо от того, вот мое взятие:

Успешный запрос:

{
  "status": "success",
  "data": {
    /* Application-specific data would go here. */
  },
  "message": null /* Or optional success message */
}

Неудачный запрос:

{
  "status": "error",
  "data": null, /* or optional error payload */
  "message": "Error xyz has occurred"
}

Преимущество: одинаковые элементы верхнего уровня как в случае успеха, так и в случае ошибки

Недостаток: нет кода ошибки, но если вы хотите, вы можете изменить статус на код (успех или неудача), или вы можете добавить еще один элемент верхнего уровня с именем «код».







Предположим, вы задали вопрос о дизайне веб-сервисов REST, а точнее об успехе / ошибке.

Я думаю, что есть 3 различных типа дизайна.

  1. Используйте только код статуса HTTP, чтобы указать, была ли ошибка, и попытайтесь ограничить себя стандартными (обычно этого должно быть достаточно).

    • Плюсы: это стандарт, независимый от вашего API.
    • Минусы: меньше информации о том, что на самом деле произошло.
  2. Используйте HTTP Status + json body (даже если это ошибка). Определите единую структуру для ошибок (например: код, сообщение, причина, тип и т. Д.) И используйте ее для ошибок, если она успешна, просто верните ожидаемый ответ json.

    • Плюсы: все еще стандартно, так как вы используете существующие коды состояния HTTP и возвращаете json с описанием ошибки (вы предоставляете больше информации о том, что произошло).
    • Минусы: выходной JSON будет варьироваться в зависимости от того, если это ошибка или успех.
  3. Забудьте статус http (например, всегда status 200), всегда используйте json и добавляйте в корень ответа логический responseValid и объект ошибки (код, сообщение и т. Д.), Который будет заполнен, если это ошибка, в противном случае другие поля (успех) заселены.

    • Плюсы: клиент имеет дело только с телом ответа, который является строкой json, и игнорирует статус (?).

    • Минусы: менее стандартные.

Выбор за вами :)

В зависимости от API я бы выбрал 2 или 3 (я предпочитаю 2 для json rest apis). Еще одна вещь, которую я испытал при разработке REST Api, — это важность документации для каждого ресурса (url): параметров, тела, ответа, заголовков и т. Д. + Примеры.

Я также рекомендую вам использовать jersey (реализация jax-rs) + genson (библиотека привязки java / json). Вам нужно всего лишь добавить genson + jersey в classpath, и json автоматически поддерживается.

РЕДАКТИРОВАТЬ:

  • Решение 2 сложнее всего реализовать, но его преимущество заключается в том, что вы можете хорошо обрабатывать исключения, а не только ошибки бизнеса. Первоначальные усилия важнее, но вы выигрываете в долгосрочной перспективе.

  • Решение 3 легко реализовать как на стороне сервера, так и на клиенте, но это не так хорошо, поскольку вам придется инкапсулировать объекты, которые вы хотите вернуть, в объект ответа, содержащий также ошибку responseValid +.








Следующее — формат Instagram, который использует Instagram

{
    "meta": {
         "error_type": "OAuthException",
         "code": 400,
         "error_message": "..."
    }
    "data": {
         ...
    },
    "pagination": {
         "next_url": "...",
         "next_max_id": "13872296"
    }
}

Я не буду так высокомерно утверждать, что это стандарт, поэтому я буду использовать форму «Я предпочитаю».

Я предпочитаю краткий ответ (при запросе списка / статей я хочу массив статей JSON).

В моих проектах я использую HTTP для отчета о состоянии, 200 возвращает только полезную нагрузку.

400 возвращает сообщение о том, что не так с запросом:

{"message" : "Missing parameter: 'param'"}

Возврат 404, если модель / контроллер / URI не существует

Если произошла ошибка с обработкой на моей стороне, я возвращаю 501 с сообщением:

{"message" : "Could not connect to data store."}

Из того, что я видел, довольно много сред REST-ish имеют тенденцию быть в этом направлении.

Обоснование :

JSON должен быть форматом полезной нагрузки , а не протоколом сеанса. Вся идея подробных полезных нагрузок сессионного выхода исходит от мира XML / SOAP и различных ошибочных решений, которые создали эти раздутые проекты. После того, как мы поняли, что все это было огромной головной болью, весь смысл REST / JSON состоял в том, чтобы поцеловать его и придерживаться HTTP. Я не думаю, что в JSend есть что-то отдаленно стандартное, особенно среди более многословных. XHR будет реагировать на HTTP-ответ, если вы используете jQuery для своего AJAX (как это делают большинство), вы можете использовать try/ catchи done()/ fail()callbacks для захвата ошибок. Я не вижу, как инкапсуляция отчетов о состоянии в JSON более полезна, чем эта.




Для чего это стоит, я делаю это по-другому. Успешный вызов просто имеет объекты JSON. Мне не нужен объект JSON более высокого уровня, который содержит поле успеха, указывающее значение true, и поле полезной нагрузки, в котором есть объект JSON. Я просто возвращаю соответствующий объект JSON с 200 или любым другим в диапазоне 200 для статуса HTTP в заголовке.

Однако, если есть ошибка (что-то из семейства 400), я возвращаю правильно сформированный объект ошибки JSON. Например, если клиент отправляет пользователя с адресом электронной почты и номером телефона, и один из них искажен (то есть я не могу вставить его в основную базу данных), я верну что-то вроде этого:

{
  "description" : "Validation Failed"
  "errors" : [ {
    "field" : "phoneNumber",
    "message" : "Invalid phone number."
  } ],
}

Важными моментами здесь являются то, что свойство field должно точно соответствовать полю JSON, которое не может быть проверено. Это позволяет клиентам точно знать, что пошло не так с их запросом. Кроме того, «сообщение» находится в локали запроса. Если оба «emailAddress» и «phoneNumber» были недействительными, то массив «errors» будет содержать записи для обоих. Тело ответа JSON 409 (конфликт) может выглядеть так:

{
  "description" : "Already Exists"
  "errors" : [ {
    "field" : "phoneNumber",
    "message" : "Phone number already exists for another user."
  } ],
}

С помощью кода состояния HTTP и этого JSON у клиента есть все, что ему нужно для детерминированного реагирования на ошибки, и он не создает новый стандарт ошибок, который пытается завершить замену кодов состояния HTTP. Обратите внимание, что это происходит только для диапазона 400 ошибок. Для всего в диапазоне 200 я могу просто вернуть все, что подходит. Для меня это часто HAL-подобный объект JSON, но здесь это не имеет значения.

Единственное, что я подумал о добавлении, это числовой код ошибки либо в записях массива «errors», либо в корне самого объекта JSON. Но пока нам это не нужно.


Они не согласны с остальными форматами ответов API-интерфейсов крупных программных гигантов — Google, Facebook, Twitter, Amazon и др., Хотя в приведенных выше ответах было приведено много ссылок, где некоторые пытались стандартизировать формат ответов.

Так как потребности API могут различаться, очень сложно привлечь всех и согласиться на какой-либо формат. Если ваши API используют миллионы пользователей, зачем менять формат ответа?

Ниже приводится мое мнение о формате ответов, вдохновленном Google, Twitter, Amazon и некоторыми публикациями в Интернете:

https://github.com/adnan-kamili/rest-api-response-format

Swagger файл:

https://github.com/adnan-kamili/swagger-sample-template






Дело в том, что JSON полностью динамичен и гибок. Согните его по своему усмотрению, потому что это просто набор сериализованных объектов и массивов JavaScript, коренящихся в одном узле.

Какой тип корневого узла зависит от вас, от того, что он содержит, зависит от вас, от вас зависит, отправляете ли вы метаданные вместе с ответом, устанавливаете ли вы mime-тип application/jsonили оставляете его text/plainна ваше усмотрение ( до тех пор, пока вы знаете, как обрабатывать крайние случаи).

Создайте легкую схему, которая вам нравится.
Лично я обнаружил , что аналитика отслеживания и mp3 / OGG сервировки и изображения галереи сервировки и текстовых сообщений и сетевые-пакеты для онлайн — игр, и блог-посты и блог-комментарии все имеют очень разные требования в плане того , что отправлено и что получено и как их нужно употреблять.

Поэтому последнее, что я хотел бы при выполнении всего этого, — это попытаться заставить каждый из них соответствовать одному и тому же стандартному стандарту, который основан на XML2.0 или что-то подобное.

Тем не менее, есть много, что можно сказать об использовании схем, которые имеют смысл для вас и хорошо продуманы.
Просто прочитайте некоторые ответы API, отметьте, что вам нравится, раскритикуйте то, что вам не нравится, запишите эти критические замечания и поймите, почему они неправильно вас теряют, а затем подумайте, как применить то, что вы узнали, к тому, что вам нужно.





JSON-RPC 2.0 определяет стандартный формат запросов и ответов и является глотком свежего воздуха после работы с REST API.




Для тех, кто придет позже, в дополнение к принятому ответу, который включает HAL, JSend и JSON API, я бы добавил несколько других спецификаций, на которые стоит обратить внимание:

  • JSON-LD , который является Рекомендацией W3C и определяет, как создавать совместимые веб-сервисы в JSON
  • Ion Hypermedia Type для REST, который заявляет о себе как «простой и интуитивно понятный гипермедиа тип на основе JSON для REST»

Предлагаемая базовая структура выглядит хорошо, но объект ошибки, как он определен, слишком ограничен. Часто для выражения проблемы нельзя использовать одно значение, а вместо этого нужна цепочка проблем и причин .

Я провел небольшое исследование и обнаружил, что наиболее распространенным форматом для возврата ошибки (исключения) является структура этой формы:

{
   "success": false,
   "error": {
      "code": "400",
      "message": "main error message here",
      "target": "approx what the error came from",
      "details": [
         {
            "code": "23-098a",
            "message": "Disk drive has frozen up again.  It needs to be replaced",
            "target": "not sure what the target is"
         }
      ],
      "innererror": {
         "trace": [ ... ],
         "context": [ ... ]
      }
   }
}

Это формат, предложенный стандартом OASIS для данных OASIS OData, и он, кажется, является наиболее стандартным вариантом, однако пока не наблюдается высоких показателей принятия какого-либо стандарта. Этот формат соответствует спецификации JSON-RPC.

Вы можете найти полную библиотеку с открытым исходным кодом, которая реализует это по адресу: Mendocino JSON Utilities . Эта библиотека поддерживает объекты JSON, а также исключения.

Подробности обсуждаются в моем блоге об обработке ошибок в JSON REST API.


Нет никакого закона о нарушении закона или закона вне закона, кроме здравого смысла. Если мы абстрагируем это как два человека, говорящих, стандарт — лучший способ, которым они могут точно понимать друг друга в минимальных словах за минимальное время. В нашем случае «минимальные слова» оптимизируют полосу пропускания для эффективности транспорта, а «точное понимание» является структурой для эффективности анализатора; что в итоге приводит к тому, что данных становится меньше, а общая структура; так что он может пройти через отверстие для булавки и может быть проанализирован через общий объем (по крайней мере, на начальном этапе).

Почти во всех предложенных случаях я вижу отдельные ответы для сценария «Успех» и «Ошибка», что для меня является двусмысленной. Если ответы в этих двух случаях различны, то почему нам действительно нужно поставить флаг «Успех»? Разве не очевидно, что отсутствие «ошибки» является «успехом»? Возможно ли получить ответ, в котором «Успех» равен «ИСТИНА» с установленным «Ошибка»? Или, кстати, «Успех» — ЛОЖЬ, а «Ошибка» не установлена? Только одного флага недостаточно? Я бы предпочел иметь только флаг «Ошибка», потому что я считаю, что будет меньше «Ошибка», чем «Успех».

Кроме того, мы должны действительно сделать флаг «Ошибка»? Что делать, если я хочу ответить с несколькими ошибками проверки? Итак, я считаю более эффективным иметь узел «Ошибка» с каждой ошибкой как дочерней по отношению к этому узлу; где пустой (считается до нуля) узел «Ошибка» будет означать «Успех».


Лучший ответ для веб-API, который может легко понять разработчики мобильных приложений.

Это для ответа «Успех»

{  
   "ReturnCode":"1",
   "ReturnMsg":"Successfull Transaction",
   "ReturnValue":"",
   "Data":{  
      "EmployeeName":"Admin",
      "EmployeeID":1
   }
}

Это для ответа «Ошибка»

{
    "ReturnCode": "4",
    "ReturnMsg": "Invalid Username and Password",
    "ReturnValue": "",
    "Data": {}
}



Общая информация

API — это программный интерфейс для внешних программных продуктов. Рассматриваемый в данном разделе API интерфейс позволяет отправлять заявки на обратный звонок, информация о которых будет загружена в журнал звонков.

Данный метод удобен тем, что не требует дополнительных действий для настройки. Нет необходимости настраивать обработчик на сервере и передавать отдельно идентификатор сессии Calltouch. ID сессии передается автоматически.

Ниже представлены функции Javascript API для получения данных о настройках виджета и отправки заявок на обратный звонок в Calltouch.

Подключение

Для подключения необходимо:

  1. Пополнить баланс минут и активировать услугу обратного звонка
  2. Создать специальный тип виджета «Форма на сайте» и настроить его.
  3. Включить виджет
  4. Добавить скрипт отправки заявок в наш сервис с помощью Javascript API.

Далее представлены варианты передаваемых параметров для отправки заявок на обратный звонок. 

Примеры обработки

Получение настроек виджета и отображение формы

window.ctw.getRouteKeyData('my_form_1', function(success, data){
    console.log(success, data);
    if (success) {
        if (data.widgetFound) {
            if (data.widgetData.callCenterWorkingMode == 'working_hours') {
                console.log('колл-центр работает, отображение виджета');
            } else {
                if (data.widgetData.collectNonWorkingRequests) {
                    console.log('колл-центр не работает, но можем отобразить форму
нерабочего времени'); } else { console.log('колл-центр не работает, заявки в нерабочее время
не собираем'); } } } else { console.log('не найден включенный виджет по routeKey, либо услуга обратного
звонка не активна'); } } else { console.log('во время обработки произошла ошибка'); console.log(data) } });

Создание заявки

window.ctw.createRequest(
    'my_form_1',
    '7xxxxxxxxxx',
    [
        {"name": "Name", "value": "Ivan"},
        {"name": "Last name", "value": "Petrov"}
    ],
    function(success, data){
        console.log(success, data)
        if (success) {
            console.log('Создана заявка на колбек, идентификатор: ' + data.callbackRequestId)
        } else {
            switch(data.type) {
                case "request_throttle_timeout":
                case "request_throttle_count":
                    console.log('Достигнут лимит создания заявок, попробуйте позже');
                    break;
                case "request_phone_blacklisted":
                    console.log('номер телефона находится в черном списке');
                    break;
                case "validation_error":
                    console.log('были переданы некорректные данные');
                    break;
                default:
                    console.log('Во время выполнения запроса произошла ошибка: ' + data.type);
            }
        }
    },
'2020-11-24 15:11:00',
[
'Тег_1',
'Тег_2'
],
12345 )

Обратите внимание, что блок с параметрами «name» и «value» имеет ограничение по количеству передаваемых полей — их может быть максимум 5, а в блоке «tags» максимум 10. Значения можно передавать как на латинице, так и на кириллице.

Значения этих полей вы можете использовать для передачи дополнительной информации ко звонку в Журнале звонков или для оповещения операторов с помощью Синтеза речи (подробнее о настройке Синтеза речи в нашей инструкции). Порядок передачи параметров в данном скрипте будет влиять на то, в каком виде они будут отображены в Журнале звонков и в каком порядке они будут проигрываться при активации Синтеза речи.

Функции

Получение данных виджета — window.ctw.getRouteKeyData

Описание функции получения данных виджета:

/**
 * Получение данных виджета
 *
 * Идентификатор формы (длина от 1 до 255)
 * @param {string} routeKey
 *
 * Функция обратного вызова для обработки результата запроса
 * @param {routeKeyDataRequestCallback} requestCallback
 */
function getRouteKeyData(routeKey, requestCallback) {},
   

Описание функции обратного вызова:

/**
 * Функция обратного вызова для обработки результата запроса получения данных виджета
 *
 * @callback routeKeyDataRequestCallback
 *
 * В случае успеха true иначе false
 * @param {bool} success
 * 
 * Данные успешного ответа или ошибки
 * @param {RouteKeyDataSuccessResponse|ErrorResponse} responseData
 */
   

Данные в случае успешного выполнения запроса получения данных виджета:

/**
 * Данные успешного выполнения запроса получения данных виджета
 *
 * @typedef {Object} RouteKeyDataSuccessResponse
 *
 * Флаг указывает найден ли виджет
 * @property {bool} widgetFound
 * 
 * Данные виджета, если widgetFound=false, то значение будет null иначе Object
 * @property {Object|null}  widgetData
 * 
 * Текущие режим работы колл-центра, возможные значения:
 * working_hours(рабочее время), non_working_hours(нерабочее время)
 * @property {string} widgetData.callCenterWorkingMode
 * 
 * Флаг указывает собирать ли заявки в нерабочее время
 * @property {bool} widgetData.collectNonWorkingRequests

* @property {Object} widgetData.workingSchedule Рабочее время колл-центра
* @property {string} widgetData.workingSchedule.utcTimezone Временная зона колл-центра
* @property {array} widgetData.workingSchedule.hours Список рабочих часов по дням недели
* @property {integer} widgetData.workingSchedule.hours[].hour Час, от 0 до 23
* @property {integer} widgetData.workingSchedule.hours[].dayOfWeek День недели, от 1 до 7
*/

Примеры данных

1. В случае когда по идентификатору формы не найдено включенного виджета или услуга обратного звонка не включена:

{
    "widgetFound":false
    "widgetData":null
}
   

2. Виджет найден:

{
     "widgetFound":true
"widgetData": {
"callCenterWorkingMode": "working_hours",
"collectRequests": true,
"workingSchedule": {
"utcTimezone": "UTC+03:00",
"hours": [
{
"hour": 9,
"dayOfWeek": 1
},
{
"hour": 10,
"dayOfWeek": 1
},
{
"hour": 11,
"dayOfWeek": 1
}
// ...
]
}
}
}

Формат данных в случае ошибки

/**
 * Данные в случае ошибки выполнения запроса
 *
 * @typedef {Object} ErrorResponse
 *
 * @property {string} type Тип ошибки
 * @property {string} message Текст ошибки
 * @property {Object} details Детали ошибки
 */
   

Возможные ошибки

Тип Описание
unknown_error Различные ошибки на клиенте (таймаут ответа сервера, сброс соединения, некорректный json в ответе, ошибочный код ответа сервера)
server_error Ошибка сервера

Создание заявки на обратный звонок — window.ctw.createRequest

Описание функции создание заявки на обратный звонок:

/**
 * Создание заявки на обратный звонок
 *
 * Идентификатор формы (длина от 1 до 255)
 * @param {string} routeKey
 * 
 * Номер телефона с кодом страны и города, без плюса (11 символов)
 * @param {string} phone
 * 
 * Дополнительные поля (не более 5 полей) или пустой массив, если нет дополнительных полей
 * @param {Object[]} fields[]
 * 
 * Название поля (длина от 1 до 15)
 * @param {string} fields[].name
 * 
 * Значение поля (длина от 1 до 35)
 * @param {string} fields[].value
 * 
 * Функция обратного вызова для обработки результата запроса
 * @param {createRequestRequestCallback} requestCallback
*
* Время в формате Y-m-d H:i:s (например 2018-02-12 22:33:00), на которое
* нужно запланировать звонок, если null то звонок будет выполнен сразу
* @param {DateTime|null} scheduleTime
*
* Пользовательские теги (не более 10 тегов) или пустой массив, если нет пользовательских тегов
* @param {Object[]} tags[]
* Значение поля (длина от 1 до 100)
* @param {string} tag
*
* Идентификатор отдела
* @param {Integer} unitId
*/
function createRequest(routeKey, phone, fields, requestCallback, scheduleTime, tags, unitId) {}

Описание функции обратного вызова:

/**
 * Функция обратного вызова для обработки результата запроса создания заявки на обратный звонок
 *
 * @callback createRequestRequestCallback
 *
 * В случае успеха true иначе false
 * @param {bool} success
 *
 * Данные успешного ответа или ошибки
 * @param {createRequestSuccessResponse|ErrorResponse} responseData
 */
   

Данные успешного выполнения запроса создание заявки на обратный звонок:

/**
 * Данные успешного выполнения запроса создание заявки на обратный звонок
 *
 * @typedef {Object} createRequestSuccessResponse
 *
 * @property {number} callbackRequestId Идентификатор заявки на обратный звонок
 */
   

Формат данных в случае ошибки

/**
 * Данные в случае ошибки выполнения запроса
 *
 * @typedef {Object} ErrorResponse
 *
 * @property {string} type Тип ошибки
 * @property {string} message Текст ошибки
 * @property {Object} details Детали ошибки
 */
   

Возможные ошибки

Тип Описание
unknown_error Различные ошибки на клиенте (таймаут ответа сервера, сброс соединения, некорректный json в ответе, ошибочный код ответа сервера)
server_error Ошибка сервера
validation_error

Ошибка при проверке корректности полей

Поле Тип Описание
fields object[] Список полей с ошибками
fields[].name string Название поля
fields[].errors object[] Список ошибок
fields[].errors[].message string Тест ошибки
request_throttle_timeout Превышен лимит на отправку заявок от данного пользователя
request_throttle_count Превышено кол-во запросов за период времени
request_phone_blacklisted Телефон в черном списке
request_widget_not_found Виджет для идентификатора формы не найден

Примеры данных

1. В случае успешного создания заявки

{
    "callbackRequestId ":231113
}
   

Примеры отображения обратного звонка

В данном примере рассмотрено создание заявки на обратный звонок с выбором отдела. Эта схема работы пригодится, если на Вашем сайте в форме есть выбор определенного дилерского центра, офиса или салона.

Для работы с отделами необходимо перейти в таб Отделы и выполнить необходимые  настройки.

mceclip1.png

В скрипте, в зависимости от выбранного салона будет подставляться id соответствующего отдела.

Тогда при выборе «РТТ-Автомаркет Хошимина» скрипт будет иметь вид:

window.ctw.createRequest(
    'test',
    '79000000000',
    [
        {"name": "Имя", "value": "Иван"},
{"name": "Отчество", "value": "Иванович"}, {"name": "Фамилия", "value": "Иванов"}
], function(success, data)
{ console.log(success, data);
},
null,
[
'Форма заявки на тестдрайв','Nissan'
],
20256 /*id отдела*/
);

В личном кабинете Calltouch в «журнале звонков» звонок отобразиться так:

mceclip0.png

Обратите внимание: отдел не отображается в «Журнале звонков», только соответствующий номер салона. Но вы можете настроить передачу тега, соответствующего отделу.

Устанавливаю сервер для сообщества POST-запросом

$url = 'https://api.vk.com/method/groups.addCallbackServer';
                      $params = array(
                      'group_id' => $d['id_group'],
                      'url' => 'https://test.ru/callback/api.php?key=0aa3e5tugzw6k6hgsoda',   // Если что скрыл название своего сайта
                      'title' => 'Сервер', 
                      'access_token' => $d['token'],  // access_token 
                      'v' => '5.73',
                                     );

                      // В $result вернется id отправленного сообщения
                      $requestpost = file_get_contents($url, false, stream_context_create(array(
                      'http' => array(
                      'method'  => 'POST',
                      'header'  => 'Content-type: application/x-www-form-urlencoded',
                      'content' => http_build_query($params)
                                      )
                       )));

Выходит такая ошибка
5a996afb1b082827491804.png

Пробывал и GET запросами и менял кодировки файла ничего не помогает, не устанавливается через API. А когда нажимаю подтвердить вручную все срабатывает, горит зеленая галочка. Как это исправить?

Есть простой бот на vk_api. Я хочу подключить его к Callback API в группе ВК через Flask. Использую хост Pythonanywere (создаю приложение). При запуске самого кода (через консоль) происходит ошибка RuntimeError: Working outside of request context. При попытке подключения к Callback API приложение просто возвращает стандартный текст. Как избавится от ошибки?

from flask import Flask, request, json
import vk_api
import vk
from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType
from vk_api.utils import get_random_id
import requests

vk_session = vk_api.VkApi(token='токен')
longpoll = VkBotLongPoll(vk_session, ID_группы)
vk = vk_session.get_api()
app = Flask(__name__)

@app.route('/', methods = ["POST"])

def main():
    data = json.loads(request.data)
    if data['type'] == 'confirmation':
        return 'код подтверждения'
    elif data['type'] == 'message_new':
        for event in longpoll.listen():
            if event.type == VkBotEventType.MESSAGE_NEW:
                if event.obj.text == '!Привет':
                    if event.from_user:
                        vk.messages.send(
                            user_id=event.user_id,
                            random_id=get_random_id(),
                            message='Привет'
                        )
                    elif event.from_chat:
                        return 'ok'
if __name__ == '__main__':
    main()

ошибка в консоли
ошибка в вк

0 / 0 / 1

Регистрация: 15.02.2017

Сообщений: 93

1

25.03.2018, 17:10. Показов 3095. Ответов 3


Студворк — интернет-сервис помощи студентам

Не могу понять как отправить ответ
Вот что нужно


Для получения уведомлений нужно подтвердить адрес сервера. На него будет отправлен POST-запрос, содержащий JSON:
{ «type»: «confirmation», «group_id»: 147772829 }
Строка, которую должен вернуть сервер: 85b38f4f

подскажите как вернуть строку на php чет не могу понять



0



Dmitry

Эксперт по компьютерным сетямЭксперт NIX

12712 / 7281 / 772

Регистрация: 09.09.2009

Сообщений: 28,443

25.03.2018, 17:13

2

PHP
1
echo json_encode(array('param1'=>'value1','param2'=>'value2'));



0



TopusT

0 / 0 / 1

Регистрация: 15.02.2017

Сообщений: 93

25.03.2018, 17:42

 [ТС]

3

Dmitry, вот что я отправил

PHP
1
echo json_encode(array("85b38f4f"));

Вот что вернуло

PHP
1
Сервер вернул неправильный ответ: ["85b38f4f"]

не знаю как убрать [«»]



0



edward_freedom

1568 / 1447 / 303

Регистрация: 01.10.2011

Сообщений: 2,636

25.03.2018, 19:27

4

Цитата
Сообщение от TopusT
Посмотреть сообщение

Строка, которую должен вернуть сервер: 85b38f4f

PHP
1
echo "85b38f4f";



1



#php #json #curl

Вопрос:

Я пытаюсь создать нового клиента в своем API, используя php cURL. Клиенты, продукты и все, что создается, создается методом POST. Это мой код:

 $json='{ "data": {  "type": "customers",  "attributes": {  "tax_registration_number": "5555555550",  "business_name": "Test customer",  "contact_name": "Mr. Test",  "website": "https://www.testurl.pt",  "phone_number": "2299999999",  "mobile_number": "9299999999",  "email": "test@testcustomer.pt",  "observations": "This is only a test",  "internal_observations": "This is good customer",  "not_final_customer": null,  "cashed_vat": null,  "tax_country_region": "PT-MA"  },  "relationships": {  "main_address": {  "data": {  "type": "addresses",  "id": 1  }  },  "addresses": {  "data": [  {  "type": "addresses",  "id": 1  },  {  "type": "addresses",  "id": 2  }  ]  }  } } }';  print($json);  

Здесь я инициирую завиток, у меня уже есть токен и авторизация:

 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,($url)); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS,($json)); curl_setopt($ch, CURLOPT_HTTPHEADER, array(  'Content-Type: application/vnd.api json',  'Accept: application/json',  'Authorization: Bearer ' . $token, )); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); var_dump ($response); $response=json_decode($response,true); curl_close ($ch);  

Это тот ответ, который у меня есть:

 string(329) "{"errors":[{"status":"500 Internal Server Error","code":"JA006","detail":"Erro de sistema JA006: erro interno na base de dados. Por favor contacte o suporte técnico.","meta":{"internal-error":"in JsonapiJson::Value::operator[](ArrayIndex)const: requires arrayValue"}}],"jsonapi":{"version": "1.0","meta":{"libversion":"2.4.1"}}}"  

Кто-нибудь, пожалуйста, может мне помочь? Спасибо!

Комментарии:

1. application/vnd.api json выглядит немного подозрительно. application/json это обычный тип содержимого JSON (как и в вашем заголовке «Принять»). Кроме того, ошибка 500 на самом деле является ошибкой на стороне сервера, поэтому вам придется связаться с сопровождающими API, чтобы выяснить, почему произошел сбой. Лично я не вижу ничего явно неправильного в вашем коде, но, возможно, кто-то еще что-то заметит

2. Вы получаете JA006 system error: internal database error. Please contact technical support. данные из API, поэтому обратитесь в их техническую поддержку

Ответ №1:

Ошибка API гласит следующее: in JsonapiJson::Value::operator[](ArrayIndex)const: requires arrayValue .

Вы уверены, что JSON-правильный формат? Похоже, что вы, вероятно, предоставляете объект в JSON, где сервер ожидает массив объектов. Например, проверьте , должны ли data , или relationships , или addresses быть массивами.

Мое главное предположение было бы вместо:

 "addresses": {  "data": [  {  "type": "addresses",  "id": 1  },  {  "type": "addresses",  "id": 2  }  ] }  

Может быть, так и должно быть

 "addresses":[  {  "type": "addresses",  "id": 1  },  {  "type": "addresses",  "id": 2  } ]  

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

  • Ошибка сервера internal server error roundcube
  • Ошибка сервера fdi при установке 1с
  • Ошибка сервера dhcp принтер xerox b215
  • Ошибка сервера dhcp 17 800 xerox 3335 workcentre
  • Ошибка сервера cups ошибка во время операции cups выполнено