Неверный юникод при отправке запроса POST в django с помощью libcurl и jsoncpp

Я создал конечную точку 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

И почтовый запрос не успешен. Мое понимание таково:

  • django-rest-framework ожидает строку json в кодировке utf-8,
  • jsoncpp кодирует строки в utf-8, и
  • libcurl не зависит от кодировки и работает с данными на байтовом уровне.

поэтому я немного удивлен этим и не уверен, как начать устранение неполадок. Может ли кто-нибудь помочь мне понять, как заставить мое приложение C ++ и приложение django работать вместе?

Спасибо!

0

Решение

В соответствии с CURLOPT_POSTFIELDS документация:

Указанные данные НЕ копируются библиотекой: как следствие, они должны сохраняться вызывающим приложением до завершения связанной передачи.. Это поведение можно изменить (поэтому libcurl копирует данные), установив CURLOPT_COPYPOSTFIELDS вариант.

Вы передаете временный char* указатель на CURLOPT_POSTFIELDS, Это потому что Json::StyledWriter::write() возвращает временный std::string что вы тогда звоните c_str() на. Когда звонок curl_easy_setopt() завершено, что std::string разрушается, и, таким образом, char* указатель, на котором держится локон, больше не действителен. Curl заканчивает тем, что передает мусорные данные из освобожденной памяти. Это неопределенное поведение, вам повезло, ваш код не просто потерпел крах.

Итак, вам нужно либо:

  1. сохранить std::string в локальной переменной до curl_easy_perform() закончен:

    std::string json = writer.write(submitted_data);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
    
  2. использование CURLOPT_COPYPOSTFIELDS вместо CURLOPT_POSTFIELDS:

    curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, writer.write(submitted_data).c_str());
    
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]