Delphi - 我的代码之简单封装WinHttpRequest

技术交流,DH讲解.

前段时间,和群里面的朋友讨论提交包的时候,结果发现Indy被大家狂批,哈哈,后来有人推荐用WinHttp,查看了下MSDN,WinHttp主要是靠system32目录下面的WinHttp.dll这个文件,而它又有2种用法,一个是直接API,复杂些,但是功能强大,另外一个就是直接使用WinHttpRequest这个ActiveX.

为了使用方便,对WinHttpRequest进行了简单封装,但是感觉不完善,有空补足.还有好多方法没有封装进来,但是留了一个属性property Http:OleVariant read FHttp write FHttp; 这样大家可以直接调用WinHttpRequest.来看看代码:(直接下载)

unit utWinHttp;

interface
uses
  SysUtils,Classes,Windows;

const
  request_headers:array[0..14] of string = (
    'Accept','Accept-Encoding','Accept-Language','Cache-Control',
    'CharSet','Connection','Content-Encoding','Content-Language',
    'Content-Type','Date','Expires','From',
    'Referer','UserAgent','Cookie'
  );

const
  WinHttpRequestOption_UserAgentString = $00000000;
  WinHttpRequestOption_URL = $00000001;
  WinHttpRequestOption_URLCodePage = $00000002;
  WinHttpRequestOption_EscapePercentInURL = $00000003;
  WinHttpRequestOption_SslErrorIgnoreFlags = $00000004;
  WinHttpRequestOption_SelectCertificate = $00000005;
  WinHttpRequestOption_EnableRedirects = $00000006;
  WinHttpRequestOption_UrlEscapeDisable = $00000007;
  WinHttpRequestOption_UrlEscapeDisableQuery = $00000008;
  WinHttpRequestOption_SecureProtocols = $00000009;
  WinHttpRequestOption_EnableTracing = $0000000A;
  WinHttpRequestOption_RevertImpersonationOverSsl = $0000000B;
  WinHttpRequestOption_EnableHttpsToHttpRedirects = $0000000C;
  WinHttpRequestOption_EnablePassportAuthentication = $0000000D;
  WinHttpRequestOption_MaxAutomaticRedirects = $0000000E;
  WinHttpRequestOption_MaxResponseHeaderSize = $0000000F;
  WinHttpRequestOption_MaxResponseDrainSize = $00000010;
  WinHttpRequestOption_EnableHttp1_1 = $00000011;
  WinHttpRequestOption_EnableCertificateRevocationCheck = $00000012;

  AutoLogonPolicy_Always = $00000000;
  AutoLogonPolicy_OnlyIfBypassProxy = $00000001;
  AutoLogonPolicy_Never = $00000002;

  SslErrorFlag_UnknownCA = $00000100;
  SslErrorFlag_CertWrongUsage = $00000200;
  SslErrorFlag_CertCNInvalid = $00001000;
  SslErrorFlag_CertDateInvalid = $00002000;
  SslErrorFlag_Ignore_All = $00003300;

  SecureProtocol_SSL2 = $00000008;
  SecureProtocol_SSL3 = $00000020;
  SecureProtocol_TLS1 = $00000080;
  SecureProtocol_ALL = $000000A8;

const
  IStream_GUID:TGUID = '{0000000C-0000-0000-C000-000000000046}';

type
  TCustomWinHttp = class;
  //请求信息类
  TRequest = class(TPersistent)
  private
    FAccept,FAcceptEncoding,FAcceptLanguage:string;
    FCacheControl,FCharSet,FConnection:string;
    FContentEncoding,FContentLanguage,FContentType:string;
    FDate,FExpires,FFrom:string;
    FReferer,FUserAgent:string;
    FCookie:string;
    FCustomHeader:TStringList;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property Accept:string  read FAccept write FAccept;
    property AcceptEncoding:string read FAcceptEncoding write FAcceptEncoding;
    property AcceptLanguage:string read FAcceptLanguage write FAcceptLanguage;
    property CacheControl:string read FCacheControl write FCacheControl;
    property CharSet:string read FCharSet write FCharSet;
    property Connection:string read FConnection write FConnection;
    property ContentEncoding:string read FContentEncoding write FContentEncoding;
    property ContentLanguage:string read FContentLanguage write FContentLanguage;
    property ContentType:string read FContentType write FContentType;
    property Date:string read FDate write FDate;
    property Expires:string read FExpires write FExpires;
    property From:string read FFrom write FFrom;
    property Referer:string read FReferer write FReferer;
    property UserAgent:string read FUserAgent write FUserAgent;
    property Cookie:string read FCookie write FCookie;
    property CustomHeader:TStringList  read FCustomHeader write FCustomHeader;
  end;
  //返回信息类
  TResponse = class(TPersistent)
  private
    FOwner:TCustomWinHttp;
    FHeaderList:TStringList;
    procedure Check;
    function Get_Header(const header_name:string):string;
    function Get_Status:Integer;
    function Get_StatusText:string;
    function Get_ResponseBody:string;
    function Get_HeadersText:string;
  public
    constructor Create(http:TCustomWinHttp);
    destructor Destroy; override;
    property Header[const Name:string]:string  read Get_Header;
    property Status:Integer  read Get_Status;
    property StatusText:string  read Get_StatusText;
    property ResponseBody:string  read Get_ResponseBody;
    property HeadersText:string read Get_HeadersText;
  end;

  TCustomWinHttp = class(TComponent)
  private
    FCreated:Boolean;
    FHttp:OleVariant;
    FRequest:TRequest;
    FResponse:TResponse;
    FRequestTime:Integer;
    FOnRequestTimeOut:TNotifyEvent;

    procedure SetRequestHeaders;
    procedure Set_Option(idx:Integer;value:OleVariant);
    function Get_Option(idx:Integer):OleVariant;

    procedure Set_Redirects(B:Boolean);
    function Get_Redirects:Boolean;

    procedure Set_MaxRedirects(N:Integer);
    function Get_MaxRedirects:Integer;
  public
    procedure Abort;
    procedure ClearRequestHeaders;
    function Get(const URL:string):string;overload;
    procedure Get(Const URL:string;res:TStream);overload;
    function Post(const URL:string;Req:TStream):string;overload;
    function Post(const URL,Req:string):string;overload;
    procedure Post(const URL:string;Req,Res:TStream);overload;
    procedure Post(const URL,Req:string;Res:TStream);overload;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    property Http:OleVariant  read FHttp write FHttp;
    property EnableRedirects:Boolean  read Get_Redirects write Set_Redirects;
    property MaxRedirects:Integer  read Get_MaxRedirects write Set_MaxRedirects;
    property Request:TRequest  read FRequest write FRequest;
    property RequestTime:Integer  read FRequestTime write FRequestTime;
    property OnRequestTimeOut:TNotifyEvent  read FOnRequestTimeOut write FOnRequestTimeOut;
    property Response:TResponse  read FResponse write FResponse;
    property Options[idx:Integer]:OleVariant  read Get_Option write Set_Option;
  end;

  TWinHttp = class(TCustomWinHttp)
  published
    property MaxRedirects;
    property EnableRedirects;
    property Request;
    property Response;
    property RequestTime;
    property OnRequestTimeOut;
  end;

implementation
uses
  ComObj,AxCtrls,ActiveX,Variants;

{ TResponse }

procedure TResponse.Check;
begin
  if FHeaderList.Count = 0 then
    FHeaderList.Text:=FOwner.FHttp.GetAllResponseHeaders;
end;

constructor TResponse.Create(http:TCustomWinHttp);
begin
  FOwner:=http;
  FHeaderList:=TStringList.Create;
  FHeaderList.NameValueSeparator:=':';
end;

destructor TResponse.Destroy;
begin
  FHeaderList.Free;
  inherited;
end;

function TResponse.Get_Header(const header_name: string): string;
begin
  Check;
  Result:=FHeaderList.Values[header_name];
end;

function TResponse.Get_HeadersText: string;
begin
  Check;
  Result:=FHeaderList.Text;
end;

function TResponse.Get_ResponseBody: string;
begin
  Result:=FOwner.Http.ResponseBody;
end;

function TResponse.Get_Status: Integer;
begin
  Result:=FOwner.Http.Status;
end;

function TResponse.Get_StatusText: string;
begin
  Result:=FOwner.Http.StatusText;
end;

{ TRequest }

constructor TRequest.Create;
begin
  inherited;
  FCustomHeader:=TStringList.Create;
end;

destructor TRequest.Destroy;
begin
  FCustomHeader.Free;
  inherited;
end;

{ TCustomWinHttp }

procedure TCustomWinHttp.Abort;
begin
  if FCreated then
    FHttp.Abort();
end;

procedure TCustomWinHttp.ClearRequestHeaders;
var
  I,base: Integer;
begin
  base := Integer(FRequest);
  for I := 0 to 14 do
    PDWORD(base + 4 * (I+1))^:=0;
  FRequest.CustomHeader.Clear;
end;

constructor TCustomWinHttp.Create(AOwner: TComponent);
begin
  inherited;
  FRequest:=TRequest.Create;
  FRequest.FCustomHeader.NameValueSeparator:=':';
  FResponse:=TResponse.Create(Self);
  try
    FCreated:=False;
    FHttp:=CreateOleObject('WinHttp.WinHttpRequest.5.1');
    FCreated:=True;
  except
    raise Exception.Create('创建WinHttp失败');
  end;

  FRequestTime:=4000;
end;

destructor TCustomWinHttp.Destroy;
begin
  Abort;
  FHttp:=0;
  FResponse.Free;
  FRequest.Free;
  inherited;
end;

function TCustomWinHttp.Get(const URL: string): string;
var
  ss:TStringStream;
begin
  Result:='';
  ss:=TStringStream.Create;
  try
    Get(URL,SS);
    Result:=ss.DataString;
  finally
    ss.Free;
  end;
end;

procedure TCustomWinHttp.Get(const URL: string; res: TStream);
var
  iu:IUnknown;
  os:TOlestream;
  s:IStream;
  p:OleVariant;
  w:Word;
begin
  Assert(res<>Nil);
  if Not FCreated then
    Exit;
  //清除已经有的header
  FResponse.FHeaderList.Clear;
  //请求
  try
    FHttp.Open('GET',URL,False);
    SetRequestHeaders;
    FHttp.Send(varEmpty);
    if Not FHttp.WaitForResponse(FRequestTime) then
    begin
      FHttp.Abort;
      if Assigned(FOnRequestTimeOut) then
        FOnRequestTimeOut(Self);
      Exit;
    end;
    P:=FHttp.ResponseStream ;
    W:=VarType(P);
    if w = varUnknown then
    begin
      iu:=IUnknown(P);
      iu.QueryInterface(IStream_GUID,s);
    end;
    if s=nil then
      Exit;
    res.Position:=0;
    os:=TOleStream.Create(s);
    try
      os.Position:=0;
      res.CopyFrom(os,os.Size)
    finally
      os.Free
    end;
  except
  end;
end;

function TCustomWinHttp.Get_MaxRedirects: Integer;
begin
  Result:=Get_Option(WinHttpRequestOption_MaxAutomaticRedirects) ;
end;

function TCustomWinHttp.Get_Option(idx: Integer): OleVariant;
begin
  Result:=FHttp.Option[idx];
end;

function TCustomWinHttp.Get_Redirects: Boolean;
begin
  Result:=FHttp.Option[WinHttpRequestOption_EnableRedirects];
end;

function TCustomWinHttp.Post(const URL, Req: string): string;
var
  ss:TStringStream;
begin
  Result:='';
  SS:=TStringStream.Create;
  try
    Post(URL,Req,SS);
    Result:=ss.DataString;
  finally
    ss.Free;
  end;
end;

function TCustomWinHttp.Post(const URL: string; Req: TStream): string;
var
  ss:TStringStream;
  S:string;
begin
  Assert(Req<>nil);
  ss:=TStringStream.Create;
  try
    Req.Position:=0;
    ss.CopyFrom(Req,Req.Size);
    S:=ss.DataString;
    ss.Clear;
    Post(URL,S,ss);
    Result:=ss.DataString;
  finally
    ss.Free;
  end;
end;

procedure TCustomWinHttp.Post(const URL: string; Req, Res: TStream);
var
  ss:TStringStream;
  S:string;

begin
  Assert(Req<>nil);
  ss:=TStringStream.Create;
  try
    Req.Position:=0;
    ss.CopyFrom(Req,Req.Size);
    S:=ss.DataString;
    Post(URL,s,Res)
  finally
    ss.Free;
  end;

end;

procedure TCustomWinHttp.SetRequestHeaders;
var
  I,dx,base: Integer;
  S:string;
begin
  base:=Integer(FRequest);
  for I := 0 to 14 do
  begin
    dx:=base + 4 * (I + 1);
    s:=PString(dx)^;
    if s<>'' then
      FHttp.SetRequestHeader(request_headers[I],S);
  end;
  for I := 0 to FRequest.CustomHeader.Count - 1 do
    FHttp.SetRequestHeader(FRequest.CustomHeader.Names[I],
            FRequest.CustomHeader.ValueFromIndex[I]
    );

end;

procedure TCustomWinHttp.Set_MaxRedirects(N: Integer);
begin
  Set_Option(WinHttpRequestOption_MaxAutomaticRedirects,N);
end;

procedure TCustomWinHttp.Set_Option(idx: Integer; value: OleVariant);
begin
  FHttp.Option[idx]:=value;
end;

procedure TCustomWinHttp.Set_Redirects(B: Boolean);
begin
  Set_Option(WinHttpRequestOption_EnableRedirects,B);
end;

procedure TCustomWinHttp.Post(const URL, Req: string; Res: TStream);
var
  s:IStream;
  os:TOleStream;
  p:OleVariant;
begin
  Assert(Res<>Nil);
  if Not FCreated then
    Exit;
  FResponse.FHeaderList.Clear;
  try
    FHttp.Open('POST',URL,False);
    SetRequestHeaders;
    FHttp.SetRequestHeader('Content-Length',IntToStr(Length(Req)));
    FHttp.Send(Req);
    if Not FHttp.WaitForResponse(FRequestTime) then
    begin
      FHttp.Abort;
      if Assigned(FOnRequestTimeOut) then
        FOnRequestTimeOut(Self);
      Exit;
    end;
    P:=FHttp.ResponseStream;
    if VarType(P) = varUnknown then
      IUnknown(P).QueryInterface(IStream_GUID,S);
    if s=nil then
      Exit;
    os:=TOleStream.Create(s);
    try
      Res.Position:=0;
      os.Position:=0;
      Res.CopyFrom(os,os.Size);
    finally
      os.Free;
    end;
  except
  end;
end;

end.


简单用法,表单提交来登录人人网:

type
  TForm3 = class(TForm)
    btn1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
    Http:TWinHttp;
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.btn1Click(Sender: TObject);
var
  s:string;
begin
  //清空之前的header
  Http.ClearRequestHeaders;
  //设置自己的header ,两种方法都可以
  //POST时候这个必须设置成这样
  Http.Request.ContentType:='application/x-www-form-urlencoded';
//  Http.Request.CustomHeader.Add('Content-Type: application/x-www-form-urlencoded');
  S:=Http.Post('http://www.renren.com/PLogin.do',
  'email=huangjacky@163.com&password=密码&origURL=http%3A%2F%2Fwww.renren.com%2FHome.do&domain=renren.com');
  //html代码
  ShowMessage(S);
  //返回的header
  ShowMessage(Http.Response.HeadersText);
  //状态
  ShowMessageFmt('Code:%D,Text:%S',
      [Http.Response.Status,Http.Response.StatusText]
    );
end;

procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Http.Free;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  Http:=TWinHttp.Create(Self);
  //禁止转向
  Http.EnableRedirects:=False;
end;

再来个下载文件的例子:

procedure TForm3.btn2Click(Sender: TObject);
var
  S:TFileStream;
begin
  s:=TFileStream.Create('C:\11.rar',fmCreate);
  Http.Get('http://files.cnblogs.com/huangjacky/Delphi.Distiller.v1.83.rar',s);
  s.Free;
end;


我是DH,吃饭去了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WinHTTP提供以下功能: WinHttpAddRequestHeaders 向HTTP请求句柄添加一个或多个HTTP请求标头。 WinHttpCheckPlatform 确定WinHTTP是否支持当前平台。 WinHttpCloseHandle 关闭单个 HINTERNET句柄。 WinHttpConnect 指定HTTP请求的初始目标服务器。 WinHttpCrackUrl 将URL分为其组成部分,例如主机名和路径。 WinHttpCreateProxyResolver 创建WinHttpGetProxyForUrlEx使用的句柄。 WinHttpCreateUrl 从组件部分创建URL,例如主机名和路径。 WinHttpDetectAutoProxyConfigUrl 查找代理自动配置(PAC)文件的URL。此功能报告PAC文件的URL,但不下载该文件。 WinHttpFreeProxyResult 释放从以前的调用WinHttpGetProxyResult检索的数据。 WinHttpGetDefaultProxyConfiguration 从注册表中检索默认的WinHTTP代理配置。 WinHTTPGetIEProxyConfigForCurrentUser 获取当前用户的Internet Explorer(IE)代理配置。 WinHttpGetProxyForUrl 检索指定URL的代理信息。 WinHttpGetProxyForUrlEx 检索指定URL的代理信息。 WinHttpGetProxyResult 检索到调用的结果WinHttpGetProxyForUrlEx。 WinHttpOpen 初始化应用程序对WinHTTP功能的使用。 WinHttpOpenRequest 创建HTTP请求句柄。 WinHttpQueryAuthSchemes 返回服务器支持的授权方案。 WinHttpQueryDataAvailable 返回可立即与读取数据的字节数 WinHttpReadData。 WinHttpQueryHeaders 检索与HTTP请求相关联的头信息。 WinHttpQueryOption 在指定的句柄上查询Internet选项。 WinHttpReadData 从WinHttpOpenRequest函数打开的句柄中读取数据 。 WinHttpReceiveResponse 结束由WinHttpSendRequest启动的HTTP请求 。 WinHttpResetAutoProxy 重置自动代理。 WinHttpSendRequest 将指定的请求发送到HTTP服务器。 WinHttpSetCredentials 将所需的授权凭证传递给服务器。 WinHttpSetDefaultProxyConfiguration 在注册表中设置默认的WinHTTP代理配置。 WinHttpSetOption 设置Internet选项。 WinHttpSetStatusCallback 设置WinHTTP可以在操作过程中进行调用的回调函数。 WinHttpSetTimeouts 设置涉及HTTP事务的各种超时。 WinHttpTimeFromSystemTime 根据HTTP版本1.0规范格式化日期和时间。 WinHttpTimeToSystemTime 获取HTTP时间/日期字符串并将其转换为 SYSTEMTIME结构。 WinHttpWriteData 将请求数据写入HTTP服务器。 WinHttpWebSocketClose 关闭WebSocket连接。 WinHttpWebSocketCompleteUpgrade 完成由WinHttpSendRequest启动的WebSocket握手。 WinHttpWebSocketQueryCloseStatus 获取服务器发送的关闭状态。 WinHttpWebSocketReceive 从WebSocket连接接收数据。 WinHttpWebSocketSend 通过WebSocket连接发送数据。 WinHttpWebSocketShutdown 向WebSocket连接发送关闭框架
### 回答1: VB中使用WinHTTPRequest下载文件十分简单,只需几行代码即可完成。 首先,我们需要创建一个WinHTTPRequest对象,并设置其相关属性。然后使用Open方法指定下载文件的URL,并使用Send方法发送下载请求。 接着,我们需要创建一个文件流对象,用于保存下载的文件内容。然后使用WinHTTPRequest的ResponseBody属性获取下载的文件内容,并将其写入文件流。 最后,关闭文件流,并释放WinHTTPRequest对象。 下面是一个简单的示例代码: ```vb Dim http As New WinHttp.WinHttpRequest Dim fileStream As Object ' 设置WinHTTPRequest的属性 http.Option(WinHttpRequestOption_EnableRedirects) = True http.Option(WinHttpRequestOption_SslErrorIgnoreFlags) = &H3300 ' 发送下载请求 http.Open "GET", "http://example.com/samplefile.txt", False http.Send ' 创建保存下载内容的文件流 Set fileStream = CreateObject("ADODB.Stream") fileStream.Type = 1 ' 二进制 ' 将下载的文件内容写入文件流 fileStream.Open fileStream.Write http.ResponseBody fileStream.SaveToFile "C:\Downloads\samplefile.txt" fileStream.Close ' 释放WinHTTPRequest对象 Set http = Nothing ``` 上述代码假设我们要下载的文件是位于`http://example.com/samplefile.txt`,并将其保存在`C:\Downloads\samplefile.txt`路径下。你可以将代码中的URL和保存路径修改为你需要的文件。 以上就是使用VB的WinHTTPRequest下载文件的简单示例,希望能够对你有所帮助! ### 回答2: 使用VBScript中的WinHttpRequest对象可以简单实现文件下载。下面是一个使用WinHttpRequest对象下载文件的简单示例: ```vbscript Dim WinHttpReq ' 声明WinHttpRequest对象 Dim url, fileName ' 定义下载文件的URL和保存的文件名 url = "http://example.com/file.pdf" ' 要下载的文件的URL fileName = "C:\Downloads\file.pdf" ' 要保存的文件路径 ' 创建WinHttpRequest对象 Set WinHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1") ' 发送GET请求以下载文件 WinHttpReq.Open "GET", url, False WinHttpReq.Send ' 检查响应状态 If WinHttpReq.Status = 200 Then ' 保存下载的文件 Set stream = CreateObject("ADODB.Stream") stream.Open stream.Type = 1 stream.Write WinHttpReq.ResponseBody stream.SaveToFile fileName, 2 stream.Close MsgBox "文件下载完成。" Else MsgBox "下载文件失败。" End If ``` 上述代码首先声明了`WinHttpRequest`对象和要下载的文件的URL以及保存的文件路径。然后创建`WinHttpRequest`对象,使用`Open`方法发送GET请求以下载文件,并使用`Send`方法发送该请求。 然后,我们检查响应状态是否为200,即请求是否成功。如果成功,我们通过创建`ADODB.Stream`对象来保存下载的文件,并使用`SaveToFile`方法将响应的`ResponseBody`写入文件流中,最后关闭流。 最后,我们使用`MsgBox`显示一个消息框,告诉用户文件是否成功下载。 请注意,下载的文件应该具有正确的权限,并且要保存的文件路径必须是存在且可写的。 ### 回答3: 在使用VB的WinHttpRequest对象下载文件时,可以按照以下步骤进行操作: 1. 首先,创建一个WinHttpRequest对象,并设置其相关属性: ``` Dim http As WinHttpRequest Set http = New WinHttpRequest http.Option(WinHttpRequestOption_EnableRedirects) = True http.Option(WinHttpRequestOption_SslErrorIgnoreFlags) = &H3300 ``` 2. 然后,使用Open方法指定请求的URL: ``` http.Open "GET", "http://example.com/file.txt", False ``` 3. 发送请求并获取响应: ``` http.Send ``` 4. 检查请求是否成功,并将响应保存到本地文件: ``` If http.Status = 200 Then Dim adodbStream As Object Set adodbStream = CreateObject("ADODB.Stream") adodbStream.Open adodbStream.Type = 1 '二进制 adodbStream.Write http.ResponseBody adodbStream.SaveToFile "C:\download\file.txt", 2 '保存到本地文件 adodbStream.Close Set adodbStream = Nothing End If ``` 以上是通过VB的WinHttpRequest对象进行文件下载的基本步骤。需要注意的是,下载文件的URL必须是有效可访问的,并且本地保存文件的路径需要存在且有写入权限。此外,还可以根据具体需求添加错误处理、进度监测等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值