Есть простой бот на 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
Не могу понять как отправить ответ
подскажите как вернуть строку на php чет не могу понять
__________________ 0 |
Dmitry 12380 / 7220 / 757 Регистрация: 09.09.2009 Сообщений: 28,177 |
||||
25.03.2018, 17:13 |
2 |
|||
0 |
TopusT 0 / 0 / 1 Регистрация: 15.02.2017 Сообщений: 93 |
||||||||
25.03.2018, 17:42 [ТС] |
3 |
|||||||
Dmitry, вот что я отправил
Вот что вернуло
не знаю как убрать [«»] 0 |
edward_freedom 1568 / 1447 / 303 Регистрация: 01.10.2011 Сообщений: 2,636 |
||||
25.03.2018, 19:27 |
4 |
|||
Строка, которую должен вернуть сервер: 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. Как оказалось, с такой ошибкой сталкиваются многие вебмастеры при обновлении или публикации записей в WordPress.
С ней же столкнулся и я при переносе сайта своего клиента с хостинга Beget на Namecheap. Кстати, консоль у меня была на английском языке, и эта ошибка звучала так: Updating failed. The response is not a valid JSON response.
В этом материале я расскажу о всех возможных способах решить эту проблему, и какой помог лично мне.
Навигация по статье
Почему возникает эта ошибка?
Причин возникновения этой ошибки множество, но самая распространенная — отключение событий REST API. Но мы не будем останавливаться только на ней и рассмотрим все возможные способы решения этой проблемы.
Кстати, так выглядит сама ошибка обновления, возникающая при публикации или обновлении записи в WordPress.
Как я решил эту проблему? Изначально я создавал сайт на хостинге Beget, после завершения работы требовалось выгрузить сайт на хостинг Namecheap. И сразу после публикации сайта я обнаружил, что больше могу обновлять или создавать новые записи/страницы. Особо никаких действий предпринимать мне не хотелось, поэтому я просто написал в техподдержку, и там решили мою проблему.
Если же техподдержка вашего хостинга не очень отзывчивая, то я рекомендую перейти на Beget и обязательно указать мой код партнера 1486766 при регистрации! 😀
А если серьезно, то попробуйте каждый из описанных ниже методов, и один из них вам наверняка поможет!
Способ 1. Обновите постоянные ссылки
Перейдите в консоль вашего сайта, затем в Настройки и найдите там пункт Постоянные ссылки.
Здесь вам требуется просто нажать на кнопку Обновить. После этого можно проверить изменения.
Способ 2. Установка классического редактора WordPress
Далеко не самый идеальный способ решения проблемы, потому что вам придется отказаться от удобного современного блочного редактора и начать пользоваться его давно устаревшей версией.
Скачайте плагин Классический редактор с официального репозитория WordPress. Затем перейдите в Настройки — Написание. Здесь вам нужно найти параметр Классический редактор для всех пользователей и выбрать значение Для всех.
Можно проверить изменения. Если не помогло, переходим к следующему способу!
Способ 3. Отсутствие SSL сертификата или его некорректная настройка
Зачастую многие регистраторы и хостинг-провайдеры предлагают слишком дорогие SSL-сертификаты, цена на которые порой превышает 5 000 рублей за год. Далеко не все готовы платить столько денег и ищут возможность подключить бесплатный SSL-сертификат.
Зачастую эти попытки заканчиваются неудачами, некорректными настройками сайта, что приводит к ряду ошибок.
Если вы новичок, то крайне рекомендую использовать хостинг Beget в своей работе. Он не только предоставляет бесплатный пробный период на 30 дней для любого тарифа, но и выдает бесплатные рабочие SSL-сертификаты. Я уже как-то писал обзор на хостинг Beget, рекомендую к прочтению!
Способ 4. Устранение ошибки смешанного содержимого
Данное решение поможет, если ошибка возникла после подключения SSL-сертификата. Для начала перейдите в раздел настроек вашего сайта и проверьте, чтобы URL WordPress Address (Адрес WordPress) и URL Site Address (Адрес сайта) начинались с протокола безопасного соединения https.
Затем перейдите в раздел плагинов, скачайте и установите Really Simple SSL. После активации плагина появится уведомление Almost Ready to migrate SSL. Нажмите на синюю кнопку Activate SSL.
Затем идем в Настройки, находим раздел 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!"
}
}
Ответы:
Да, есть пара стандартов (хотя и с определенными свободами в определении стандарта):
- JSON API — JSON API охватывает также создание и обновление ресурсов, а не только ответы.
- JSend — Простой и, вероятно, то, что вы уже делаете.
- OData JSON Protocol — очень сложный.
- 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 различных типа дизайна.
-
Используйте только код статуса HTTP, чтобы указать, была ли ошибка, и попытайтесь ограничить себя стандартными (обычно этого должно быть достаточно).
- Плюсы: это стандарт, независимый от вашего API.
- Минусы: меньше информации о том, что на самом деле произошло.
-
Используйте HTTP Status + json body (даже если это ошибка). Определите единую структуру для ошибок (например: код, сообщение, причина, тип и т. Д.) И используйте ее для ошибок, если она успешна, просто верните ожидаемый ответ json.
- Плюсы: все еще стандартно, так как вы используете существующие коды состояния HTTP и возвращаете json с описанием ошибки (вы предоставляете больше информации о том, что произошло).
- Минусы: выходной JSON будет варьироваться в зависимости от того, если это ошибка или успех.
-
Забудьте статус 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.
Подключение
Для подключения необходимо:
- Пополнить баланс минут и активировать услугу обратного звонка
- Создать специальный тип виджета «Форма на сайте» и настроить его.
- Включить виджет
- Добавить скрипт отправки заявок в наш сервис с помощью 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 |
Ошибка при проверке корректности полей
|
|||||||||||||||
request_throttle_timeout | Превышен лимит на отправку заявок от данного пользователя | |||||||||||||||
request_throttle_count | Превышено кол-во запросов за период времени | |||||||||||||||
request_phone_blacklisted | Телефон в черном списке | |||||||||||||||
request_widget_not_found | Виджет для идентификатора формы не найден |
Примеры данных
1. В случае успешного создания заявки
{ "callbackRequestId ":231113 }
Примеры отображения обратного звонка
В данном примере рассмотрено создание заявки на обратный звонок с выбором отдела. Эта схема работы пригодится, если на Вашем сайте в форме есть выбор определенного дилерского центра, офиса или салона.
Для работы с отделами необходимо перейти в таб Отделы и выполнить необходимые настройки.
В скрипте, в зависимости от выбранного салона будет подставляться id соответствующего отдела.
Тогда при выборе «РТТ-Автомаркет Хошимина» скрипт будет иметь вид:
window.ctw.createRequest( 'test', '79000000000', [ {"name": "Имя", "value": "Иван"},
{"name": "Отчество", "value": "Иванович"}, {"name": "Фамилия", "value": "Иванов"}
], function(success, data)
{ console.log(success, data);
},
null,
[
'Форма заявки на тестдрайв','Nissan'
],
20256 /*id отдела*/
);
В личном кабинете Calltouch в «журнале звонков» звонок отобразиться так:
Обратите внимание: отдел не отображается в «Журнале звонков», только соответствующий номер салона. Но вы можете настроить передачу тега, соответствующего отделу.
Устанавливаю сервер для сообщества 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)
)
)));
Выходит такая ошибка
Пробывал и 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
Не могу понять как отправить ответ
подскажите как вернуть строку на php чет не могу понять
0 |
Dmitry 12712 / 7281 / 772 Регистрация: 09.09.2009 Сообщений: 28,443 |
||||
25.03.2018, 17:13 |
2 |
|||
0 |
TopusT 0 / 0 / 1 Регистрация: 15.02.2017 Сообщений: 93 |
||||||||
25.03.2018, 17:42 [ТС] |
3 |
|||||||
Dmitry, вот что я отправил
Вот что вернуло
не знаю как убрать [«»]
0 |
edward_freedom 1568 / 1447 / 303 Регистрация: 01.10.2011 Сообщений: 2,636 |
||||
25.03.2018, 19:27 |
4 |
|||
Строка, которую должен вернуть сервер: 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, который вы пытаетесь использовать, но я сильно подозреваю, что это такой случай, когда он ожидает массив, но вы предоставляете объект.