c++ - 使用 libcurl 和 jsoncpp 向 django 发送 POST 请求时无效的 unicode

标签 c++ django django-rest-framework libcurl jsoncpp

我使用 rest-framework 模块在 Django 中创建了一个 REST 端点;简单的代码如下:

模型.py

class Data(models.Model):
    name = models.CharField(max_length=256)
    description = models.TextField()

    def __str__(self):
        return self.name

序列化器.py

class DataSerializer(serializers.ModelSerializer):
    class Meta:
        model = Data
        fields = ('name', 'description')

View .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)

我已经尝试使用 Firefox 的 RESTClient 插件发送 POST 请求,并且可以验证它是否按原样工作。

但是,我的用例是我想在 C++ 应用程序中使用 libcurl 写入数据库。

如果我使用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 需要一个 utf-8 编码的 json 字符串,
  • jsoncpp 以 utf-8 编码字符串,并且
  • libcurl 与编码无关,并在字节级别处理数据。

所以我对此感到有点惊讶,并且不确定如何开始进行故障排除。谁能帮我弄清楚如何让我的 C++ 应用程序和 Django 应用程序协同工作?

谢谢!

最佳答案

根据 CURLOPT_POSTFIELDS documentation :

The data pointed to is NOT copied by the library: as a consequence, it must be preserved by the calling application until the associated transfer finishes. This behaviour can be changed (so libcurl does copy the data) by setting the CURLOPT_COPYPOSTFIELDS option.

您正在将一个临时 char* 指针传递给CURLOPT_POSTFIELDS。这是因为 Json::StyledWriter::write() 返回一个临时 std::string ,然后您调用 c_str( ) 上。当对 curl_easy_setopt() 的调用完成时,那个 std::string 被销毁,因此 curl 持有的 char* 指针to 不再有效。 Curl 最终从释放的内存中传输垃圾数据。这是未定义的行为,您很幸运您的代码没有完全崩溃。

因此,您需要:

  1. curl_easy_perform() 完成之前将 std::string 保存在局部变量中:

    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());
    

关于c++ - 使用 libcurl 和 jsoncpp 向 django 发送 POST 请求时无效的 unicode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40663289/

相关文章:

c++ - 现代 C++ 编译器可以内联 cpp 文件中定义的函数吗

c++ - gmock ElementsAreArray() Matcher 在 gmock-matchers.h 中给出编译器错误

Django PostgreSQL 成功syncdb后没有这样的表错误

python - 使用 MongoEngine 和 Q 构建查询抛出 InvalidQueryError

Django Rest Framework 在网站内重用 API 逻辑

c++ - 如何在 cmake 工具链文件中获取项目根目录,这可能吗?

c++ - 在销毁派生成员之前在析构函数中调用公共(public)函数

python - 如何将 2 个 django 查询合并为一个具有对象限制的查询

django - 覆盖 Django rest ViewSet 中的列表方法

python - 如何使用模型序列化程序序列化 django-rest 中的一对多关系?