Я создал конечную точку REST в Django, используя модуль rest-framework; простой код выглядит так:
models.py
class Data(models.Model):
name = models.CharField(max_length=256)
description = models.TextField()
def __str__(self):
return self.name
serializers.py
class DataSerializer(serializers.ModelSerializer):
class Meta:
model = Data
fields = ('name', 'description')
views.py
def data_list(request):
"""List all data.
"""if request.method == 'GET':
categories = Data.objects.all()
serializer = DataSerializer(categories, many=True)
return JSONResponse(serializer.data)
elif request.method == 'POST':
data = JSONParser().parse(request)
serializer = DataSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400)
Я попытался отправить запросы POST с помощью плагина RESTClient для Firefox, и могу проверить, что он работает как есть.
Тем не менее, мой вариант использования заключается в том, что я хотел бы написать в базу данных, используя libcurl в приложении C ++.
Если я использую jsoncpp для создания объекта JSON, а затем использую libcurl для выполнения запроса POST, как показано ниже:
void main() {
Json::Value submitted_data;
submitted_data["name"] = "data id";
submitted_data["description"] = "data description";
Json::StyledWriter writer;
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:8000/data/");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json; charset=UTF-8");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, writer.write(submitted_data).c_str());
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
}
Я получаю сообщение об ошибке от сервера django:
File "C:\Python27\lib\site-packages\rest_framework\parsers.py", line 67, in parse
raise ParseError('JSON parse error - %s' % six.text_type(exc))
ParseError: JSON parse error - 'utf8' codec can't decode byte 0xdd in position 0: invalid continuation byte
И почтовый запрос не успешен. Мое понимание таково:
поэтому я немного удивлен этим и не уверен, как начать устранение неполадок. Может ли кто-нибудь помочь мне понять, как заставить мое приложение C ++ и приложение django работать вместе?
Спасибо!
В соответствии с CURLOPT_POSTFIELDS
документация:
Указанные данные НЕ копируются библиотекой: как следствие, они должны сохраняться вызывающим приложением до завершения связанной передачи.. Это поведение можно изменить (поэтому libcurl копирует данные), установив
CURLOPT_COPYPOSTFIELDS
вариант.
Вы передаете временный char*
указатель на CURLOPT_POSTFIELDS
, Это потому что Json::StyledWriter::write()
возвращает временный std::string
что вы тогда звоните c_str()
на. Когда звонок curl_easy_setopt()
завершено, что std::string
разрушается, и, таким образом, char*
указатель, на котором держится локон, больше не действителен. Curl заканчивает тем, что передает мусорные данные из освобожденной памяти. Это неопределенное поведение, вам повезло, ваш код не просто потерпел крах.
Итак, вам нужно либо:
сохранить std::string
в локальной переменной до curl_easy_perform()
закончен:
std::string json = writer.write(submitted_data);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
использование CURLOPT_COPYPOSTFIELDS
вместо CURLOPT_POSTFIELDS
:
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, writer.write(submitted_data).c_str());
Других решений пока нет …