CURL框架进行http请求

#include <stdio.h>
#include <string>
#include <iostream>
#include "curl/curl.h"
#include "httpclient.h"
//#pragma comment(lib, "libcurl.lib") 


#define qDebug()   std::cout


httpclient::httpclient()
{
}


httpclient::~httpclient()
{
  curl_global_cleanup();
}



static char error_buffer[CURL_ERROR_SIZE];
static int writer(char*, size_t, size_t, std::string*);
static bool init(CURL*&, const char*, std::string*);


static bool init(CURL*& conn, const char* url, std::string* p_buffer)
{
	CURLcode code;
    curl_slist  *headers=NULL;

	 conn = curl_easy_init();
	if (NULL == conn)
	{
        qDebug()<< " Failed to create CURL connection" ;
        //exit(EXIT_FAILURE);
        return false;
	}

    headers = curl_slist_append(headers, "Content-type:application/json");

    code  =curl_easy_setopt(conn, CURLOPT_HTTPHEADER, headers);
    if (code != CURLE_OK)
    {
         qDebug()<< " Failed to set error buffer " << code;
        return false;
    }

	code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, error_buffer);
	if (code != CURLE_OK)
	{
        qDebug()<<" Failed to set error buffer " << code;
		return false;
	}

    curl_easy_setopt(conn, CURLOPT_VERBOSE, 1L);

	code = curl_easy_setopt(conn, CURLOPT_URL, url);
	if (code != CURLE_OK)
	{
        qDebug()<< " Failed to set URL " << error_buffer;
		return false;
	}

	code = curl_easy_setopt(conn, CURLOPT_FOLLOWLOCATION, 1);
	if (code != CURLE_OK)
	{
        qDebug()<<" Failed to set redirect option " << error_buffer;
		return false;
	}

	code = curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writer);
	if (code != CURLE_OK)
	{
        qDebug()<< " Failed to set writer " << error_buffer;
		return false;
	}

	code = curl_easy_setopt(conn, CURLOPT_WRITEDATA, p_buffer);
	if (code != CURLE_OK)
	{
        qDebug()<< " Failed to set write data " << error_buffer;
		return false;
	}

	return true;
}

static int writer(char* data, size_t size, size_t nmemb, std::string* writer_data)
{
	unsigned long sizes = size * nmemb;

	if (NULL == writer_data)
	{
		return 0;
	}

	writer_data->append(data, sizes);

	return sizes;
}


int httpclient::http_get(const char* url,const std::string heads[],int len, std::string& buffer, std::string& errinfo)
{
    int ret = 0;
    CURL *conn = NULL;
    CURLcode code;
    curl_global_init(CURL_GLOBAL_DEFAULT);
    buffer.clear();

    curl_slist  *headers=NULL;
     std::string* p_buffer = &buffer;

     conn = curl_easy_init();
    if (NULL == conn)
    {
        qDebug()<< " Failed to create CURL connection" ;
        return -1;
    }

    headers = curl_slist_append(headers, "Content-type:application/json");

    for(int index =0;index<len;index++)
    {
     headers = curl_slist_append(headers, heads[index].c_str());
    }
    code  =curl_easy_setopt(conn, CURLOPT_HTTPHEADER, headers);
    if (code != CURLE_OK)
    {
         qDebug()<< " Failed to set error buffer " << code;
         ret = -1;
         goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, error_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set error buffer " << code;
        ret = -1;
        goto exit_http;
    }

    curl_easy_setopt(conn, CURLOPT_VERBOSE, 1L);

    code = curl_easy_setopt(conn, CURLOPT_URL, url);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set URL " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_FOLLOWLOCATION, 1);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set redirect option " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set writer " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEDATA, p_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set write data " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_perform(conn);

    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to post " << url << error_buffer;

        errinfo.append("Failed to post ");
        errinfo.append(url);

        ret = -2;
        goto exit_http;
    }

 exit_http:
    curl_easy_cleanup(conn);
    return ret;
}




int httpclient::http_post_map(const char* url, const char* data, const std::string heads[],int len,std::string& buffer, std::string& errinfo)
{ 
    int ret = 0;
    CURL *conn = NULL;
    CURLcode code;
    curl_global_init(CURL_GLOBAL_DEFAULT);
    buffer.clear();

    curl_slist  *headers=NULL;
     std::string* p_buffer = &buffer;

     conn = curl_easy_init();
    if (NULL == conn)
    {
        qDebug()<< " Failed to create CURL connection" ;
        return -1;
    }

//    headers = curl_slist_append(headers, "Content-type:application/json");
      headers = curl_slist_append(headers, "Connection:keep-alive");
    for(int index =0;index<len;index++)
    {
     headers = curl_slist_append(headers, heads[index].c_str());
    }
    code  =curl_easy_setopt(conn, CURLOPT_HTTPHEADER, headers);
    if (code != CURLE_OK)
    {
         qDebug()<< " Failed to set error buffer " << code;
         ret = -1;
         goto exit_http;
    }

//    curl_easy_setopt(conn, CURLOPT_INTERFACE, "eth0"); //设置使用哪种网络请求接口

    code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, error_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set error buffer " << code;
        ret = -1;
        goto exit_http;
    }

    curl_easy_setopt(conn, CURLOPT_VERBOSE, 1L);

    code = curl_easy_setopt(conn, CURLOPT_URL, url);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set URL " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_FOLLOWLOCATION, 1);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set redirect option " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set writer " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEDATA, p_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set write data " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_POST, true);

    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set CURLOPT_POST " << error_buffer ;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_POSTFIELDS, data);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set CURLOPT_POSTFIELDS " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_perform(conn);

    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to post " << url << error_buffer;

        errinfo.append("Failed to post ");
        errinfo.append(url);

        ret = -2;
        goto exit_http;
    }

 exit_http:
    curl_easy_cleanup(conn);
    return ret;
}


int httpclient::http_post(const char* url, const char* data, const std::string heads[],int len,std::string& buffer, std::string& errinfo)
{
    int ret = 0;
    CURL *conn = NULL;
    CURLcode code;
    curl_global_init(CURL_GLOBAL_DEFAULT);
    buffer.clear();

    curl_slist  *headers=NULL;
     std::string* p_buffer = &buffer;

     conn = curl_easy_init();
    if (NULL == conn)
    {
        qDebug()<< " Failed to create CURL connection" ;
        return -1;
    }

    headers = curl_slist_append(headers, "Content-type:application/json");

    for(int index =0;index<len;index++)
    {
     headers = curl_slist_append(headers, heads[index].c_str());
    }
    code  =curl_easy_setopt(conn, CURLOPT_HTTPHEADER, headers);
    if (code != CURLE_OK)
    {
         qDebug()<< " Failed to set error buffer " << code;
         ret = -1;
         goto exit_http;
    }

//    curl_easy_setopt(conn, CURLOPT_INTERFACE, "eth0"); //设置使用哪种网络请求接口

    code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, error_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set error buffer " << code;
        ret = -1;
        goto exit_http;
    }

    curl_easy_setopt(conn, CURLOPT_VERBOSE, 1L);

    code = curl_easy_setopt(conn, CURLOPT_URL, url);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set URL " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_FOLLOWLOCATION, 1);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set redirect option " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    //设置超时时间 连接超时时间 如果为0则无限等待
    code = curl_easy_setopt(conn, CURLOPT_CONNECTTIMEOUT, 10);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set CURLOPT_CONNECTTIMEOUT " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    //执行超时时间( DNS解析+连接+提交请求数据+获取请求数据? 或是 提交请求数据+获取请求数据 ?)
    code = curl_easy_setopt(conn, CURLOPT_CONNECTTIMEOUT, 10);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set CURLOPT_CONNECTTIMEOUT " << error_buffer;
        ret = -1;
        goto exit_http;
    }



    code = curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set writer " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEDATA, p_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set write data " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_POST, true);

    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set CURLOPT_POST " << error_buffer ;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_POSTFIELDS, data);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set CURLOPT_POSTFIELDS " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_perform(conn);

    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to post " << url << error_buffer;

        errinfo.append("Failed to post ");
        errinfo.append(url);

        ret = -2;
        goto exit_http;
    }

 exit_http:
    curl_easy_cleanup(conn);
    return ret;
}


int httpclient::http_post_withsign(const char* url, const char* data, std::string& buffer, std::string& errinfo,std::string &sign)
{
    int ret = 0;
    CURL *conn = NULL;
    CURLcode code;
    curl_global_init(CURL_GLOBAL_DEFAULT);
    buffer.clear();

    curl_slist  *headers=NULL;
     std::string* p_buffer = &buffer;

     conn = curl_easy_init();
    if (NULL == conn)
    {
        qDebug()<< " Failed to create CURL connection" ;
        return -1;
    }

    headers = curl_slist_append(headers, "Content-type:application/json");

    std::string signappend = "sign: "+sign; //SIGN:1234343545
    headers = curl_slist_append(headers, signappend.c_str());

    code  =curl_easy_setopt(conn, CURLOPT_HTTPHEADER, headers);
    if (code != CURLE_OK)
    {
         qDebug()<< " Failed to set error buffer " << code;
         ret = -1;
         goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_ERRORBUFFER, error_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set error buffer " << code;
        ret = -1;
        goto exit_http;
    }

    curl_easy_setopt(conn, CURLOPT_VERBOSE, 1L);

    code = curl_easy_setopt(conn, CURLOPT_URL, url);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set URL " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_FOLLOWLOCATION, 1);
    if (code != CURLE_OK)
    {
        qDebug()<<" Failed to set redirect option " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEFUNCTION, writer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set writer " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_WRITEDATA, p_buffer);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set write data " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_POST, true);

    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set CURLOPT_POST " << error_buffer ;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_setopt(conn, CURLOPT_POSTFIELDS, data);
    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to set CURLOPT_POSTFIELDS " << error_buffer;
        ret = -1;
        goto exit_http;
    }

    code = curl_easy_perform(conn);

    if (code != CURLE_OK)
    {
        qDebug()<< " Failed to post " << url << error_buffer;

        errinfo.append("Failed to post ");
        errinfo.append(url);

        ret = -2;
        goto exit_http;
    }

 exit_http:
    curl_easy_cleanup(conn);
    return ret;
}


static size_t write_filedata(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
  std::cout<<".";
  return written;
}


 int httpclient::http_filedownload(const char* url, const char* filepath,std::string& errinfo)
 {
     int err =0;
   // cout<<"download url :" <<url <<endl;

      CURL *curl_handle;
      FILE *pagefile;
      CURLcode code;

      curl_global_init(CURL_GLOBAL_ALL);

      /* init the curl session */
      curl_handle = curl_easy_init();

      /* set URL to get here */
      curl_easy_setopt(curl_handle, CURLOPT_URL, url);

      /* Switch on full protocol/debug output while testing */
      curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);

      /* disable progress meter, set to 0L to enable and disable debug output */
      curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);

      /* send all data to this function  */
      curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_filedata);

      /* open the file */
      pagefile = fopen(filepath, "w+");
      if (pagefile) {

        /* write the page body to this file handle */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);

        /* get it! */
        code = curl_easy_perform(curl_handle);
       /* Check for errors */
        if(code != CURLE_OK)
        {
            err = -2;
        }

        /* close the header file */
        fclose(pagefile);
      }
      else
      {
         err =-3;
      }

      /* cleanup curl stuff */
      curl_easy_cleanup(curl_handle);

      return err;

 }



 int httpclient::http_filedownload_withparam(const char* url, const char* data,const char* filepath,std::string& errinfo)
 {
     int err =0;
   // cout<<"download url :" <<url <<endl;

      CURL *curl_handle;
      FILE *pagefile;
      CURLcode code;

      curl_global_init(CURL_GLOBAL_ALL);

      /* init the curl session */
      curl_handle = curl_easy_init();

      /* set URL to get here */
      curl_easy_setopt(curl_handle, CURLOPT_URL, url);

      /* Switch on full protocol/debug output while testing */
      curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);

      /* disable progress meter, set to 0L to enable and disable debug output */
      curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);

      /* send all data to this function  */
      curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_filedata);

      code = curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data);
      if (code != CURLE_OK)
      {
          qDebug()<< " Failed to set CURLOPT_POSTFIELDS " << error_buffer;
          err = -1;
          return err;
      }

      /* open the file */
      pagefile = fopen(filepath, "w+");
      if (pagefile) {

        /* write the page body to this file handle */
        curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);

        /* get it! */
        code = curl_easy_perform(curl_handle);
       /* Check for errors */
        if(code != CURLE_OK)
        {
            err = -2;
        }

        /* close the header file */
        fclose(pagefile);
      }
      else
      {
         err =-3;
      }

      /* cleanup curl stuff */
      curl_easy_cleanup(curl_handle);

      return err;

 }

 int httpclient::http_filedownload(const char* url, const char* filepath,long resumefrom,long totalsize,std::string& errinfo)
 {
       int err =0;
       // cout<<"download url :" <<url <<endl;

       CURL *curl_handle;
       FILE *pagefile;
       CURLcode code;

       curl_global_init(CURL_GLOBAL_ALL);

       /* init the curl session */
       curl_handle = curl_easy_init();

       /* set URL to get here */
       curl_easy_setopt(curl_handle, CURLOPT_URL, url);

       /* Switch on full protocol/debug output while testing */
       curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);

       /* disable progress meter, set to 0L to enable and disable debug output */
       curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);


        curl_easy_setopt(curl_handle, CURLOPT_RESUME_FROM, resumefrom);

       /* send all data to this function  */
       curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_filedata);

       /* open the file */
       if(resumefrom==0)
       {
         //从0开始则删除源文件重新下载
         pagefile = fopen(filepath, "w+");
       }
       else
       {
         //非0的位置,原文件必须存在,下载的数据在源文件追加写入
         pagefile = fopen(filepath, "ab+");
       }
       if (pagefile) {

         /* write the page body to this file handle */
         curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);

         /* get it! */
         code = curl_easy_perform(curl_handle);
        /* Check for errors */
         if(code != CURLE_OK)
         {
             err = -2;
         }

         /* close the header file */
         fclose(pagefile);
       }
       else
       {
          err =-3;
       }

       /* cleanup curl stuff */
       curl_easy_cleanup(curl_handle);

       return err;
 }



 static size_t save_header(void *ptr, size_t size, size_t nmemb, void *data)
 {
    return (size_t)(size * nmemb);
 }


 int httpclient::http_getfile_length(const char *url, long &file_length, std::string &errinfo)
 {
     int err =0;
   // cout<<"download url :" <<url <<endl;

      CURL *curl_handle;
      FILE *pagefile;
      CURLcode code;

      curl_global_init(CURL_GLOBAL_ALL);

      /* init the curl session */
      curl_handle = curl_easy_init();

      /* set URL to get here */
      curl_easy_setopt(curl_handle, CURLOPT_URL, url);

      /* Switch on full protocol/debug output while testing */
      curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);

      /* disable progress meter, set to 0L to enable and disable debug output */
      curl_easy_setopt(curl_handle, CURLOPT_NOBODY, 1L);

      /* send all data to this function  */
      curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, save_header);


        /* get it! */
        code = curl_easy_perform(curl_handle);
       /* Check for errors */
        if(code != CURLE_OK)
        {
            err = -2;
        }
        else
        {
            if(CURLE_OK == curl_easy_getinfo(curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &file_length)){
                err =0;
               printf("Get  %s %d\n",url,file_length);
            }else {
                      printf("curl_easy_getinfo failed!\n");
                      err = -1;
            }
        }

      /* cleanup curl stuff */
      curl_easy_cleanup(curl_handle);

      return err;
 }




 size_t WriteToString(void *buffer, size_t size, size_t nmemb, void *userp)
 {
     (*((std::string*)userp)).append((char*)buffer, size * nmemb);

     return size * nmemb;
 }


int  httpclient::http_upload(const char* url, const char* filepath,std::string& errinfo)
{

    CURL*  curl_handle_ = curl_easy_init();

    // 重置参数
    curl_easy_reset(curl_handle_);

    // 设置http请求行
    curl_easy_setopt(curl_handle_, CURLOPT_URL, url);

    // 设置http头
    struct curl_slist* headers = NULL;
    std::string authorization = "POSNAME: M703F"; //SIGN:1234343545
    headers = curl_slist_append(headers, authorization.c_str());
    curl_easy_setopt(curl_handle_, CURLOPT_HTTPHEADER, headers);


    curl_easy_setopt(curl_handle_, CURLOPT_VERBOSE, 1L);


    // 设置https选项
    curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYPEER, false);
    curl_easy_setopt(curl_handle_, CURLOPT_SSL_VERIFYHOST, false);

    //设置回调函数
    curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION, WriteToString);
    curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, &errinfo);
    curl_easy_setopt(curl_handle_, CURLOPT_CONNECTTIMEOUT, 6L);
    curl_easy_setopt(curl_handle_, CURLOPT_TIMEOUT, 10L);

    // 设置表单数据
    struct curl_httppost* post = NULL;
    struct curl_httppost* last = NULL;

    curl_formadd(
        &post, &last,
        CURLFORM_COPYNAME, "upfile",
        CURLFORM_FILE, filepath,
        CURLFORM_FILENAME, filepath,
        CURLFORM_END);


    curl_easy_setopt(curl_handle_, CURLOPT_HTTPPOST, post);

    int rsp_code = 0;
    CURLcode res = curl_easy_perform(curl_handle_);
    if (res == CURLE_OK)
    {
        curl_easy_getinfo(curl_handle_, CURLINFO_RESPONSE_CODE, &rsp_code);
    }
    else
    {
        printf( "upload failed, errorcode = %d, res = %d, resmessage = %s", rsp_code, res, errinfo.c_str());
    }

    curl_formfree(post);
    curl_slist_free_all(headers);

    return res;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值