ServletRequest 和 HttpServletRequest 接口详解

目录

1、Servlet 处理 HTTP 请求的流程

2、ServletRequest 接口

3、HttpServletRequest 接口

(1)从HttpServletRequest获取请求行信息

(2)从HttpServletRequest 获取请求头信息

(3)从HttpServletRequest获取 form 表单的数据

(4)附:URL和URI的区别

4、HttpServletRequest 中文乱码问题

(1)POST 请求解决中文乱码问题

(2)GET 请求解决中文乱码问题

5、Tomcat 中创建 HttpServletRequest 对象的源码分析

6、Servlet 容器在接收到客户端请求时会创建哪些对象?


1、Servlet 处理 HTTP 请求的流程

        一般情况下,浏览器(客户端)通过 HTTP 协议来访问服务器的资源,Servlet 主要用来处理 HTTP 请求。Servlet 处理 HTTP 请求的流程如下:

  1. Servlet 容器接收到来自客户端的 HTTP 请求后,Servlet容器会针对该请求分别创建一个 HttpServletRequest 对象和 HttpServletReponse 对象
  2. 容器将 HttpServletRequest 对象和 HttpServletReponse 对象以参数的形式传入 service() 方法内,并调用该方法。
  3. 在 service() 方法中 Servlet 通过 HttpServletRequest 对象获取客户端信息以及请求的相关信息。
  4. 对 HTTP 请求进行处理。
  5. 请求处理完成后,将响应信息封装到 HttpServletReponse 对象中。
  6. Servlet 容器将响应信息返回给客户端。
  7. 当 Servlet 容器将响应信息返回给客户端后,HttpServletRequest 对象和 HttpServletReponse 对象被销毁。

        通过以上流程可以看出, HttpServletRequest 和 HttpServletReponse 是 Servlet 处理 HTTP 请求流程中最重要的两个对象。HttpServletRequest 对象用于封装 HTTP 请求信息,HttpServletReponse 对象用于封装 HTTP 响应信息。

        下面我们将对 HttpServletRequest 和 ServletRequest 接口进行详细介绍。

2、ServletRequest 接口

        ServletRequest接口是Java Servlet API中的一个接口,用于访问Servlet容器接收到的HTTP请求的信息。ServletRequest接口定义了一系列方法,用于获取HTTP请求的参数、属性、输入流等信息,以及对这些信息的操作。以下是ServletRequest接口中的一些具体方法:        

  1. getProtocol():返回请求使用的协议的名称和版本号。例如,HTTP/1.1。
  2. getScheme():返回请求的协议名称。例如,http、https。
  3. getServerName():返回接收请求的服务器的名称。
  4. getServerPort():返回接收请求的服务器的端口号。
  5. getRemoteAddr():返回客户端的IP地址。
  6. getRemoteHost():返回客户端的主机名。
  7. getRemotePort():返回客户端的端口号。
  8. getLocalAddr():返回服务器的IP地址。
  9. getLocalName():返回服务器的主机名。
  10. getLocalPort():返回服务器的端口号。
  11. getParameter(String name):返回请求参数的值,如果请求参数不存在,则返回null。
  12. getParameterNames():返回请求参数的名称的枚举。
  13. getParameterValues(String name):返回请求参数的值的数组,如果请求参数不存在,则返回null。
  14. getAttribute(String name):返回指定属性名称的属性值,如果属性不存在,则返回null
  15. getAttributeNames():返回所有属性名称的枚举。
  16. setAttribute(String name, Object value):将指定属性名称的属性值设置为指定的值。
  17. removeAttribute(String name):从请求中删除指定名称的属性。
  18. getLocale():返回客户端的首选语言环境。
  19. getLocales():返回客户端的所有语言环境。
  20. getCharacterEncoding():返回请求字符编码的名称,如果字符编码未指定,则返回null。
  21. getContentLength():返回请求的正文的长度,以字节为单位。
  22. getContentType():返回请求正文的MIME类型。
  23. getInputStream():返回请求正文的InputStream。
  24. getReader():返回请求正文的Reader。
  25. getProtocol():返回请求使用的协议的名称和版本号。
  26. getRemoteUser():返回发出请求的用户的登录名,如果用户未经过身份验证,则返回null。
  27. isSecure():返回请求是否通过安全连接传输。
  28. getRequestDispatcher(String path):返回用于将请求转发到另一个资源的RequestDispatcher对象。
  29. getRealPath(String path):返回指定虚拟路径的真实路径。
  30. getRequestURI():返回请求的URI,不包括查询字符串。
  31. getRequestURL():返回请求的URL,包括协议,服务器名称,端口号和请求URI,但不包括查询字符串。
  32. getServletPath():返回Servlet的路径。
  33. getSession():返回与此请求相关联的会话,如果请求没有会话,则创建一个新会话。
  34. getSession(boolean create):返回与此请求相关联的会话,如果请求没有会话,则根据指定的create参数创建一个新会话或不创建。
  35. isRequestedSessionIdValid():返回请求的会话ID是否仍然有效。
  36. isRequestedSessionIdFromCookie():返回请求是否使用Cookie来检索会话ID。
  37. isRequestedSessionIdFromURL():返回请求是否将会话ID附加到URL中。
  38. isRequestedSessionIdFromUrl():已过时的方法,等效于isRequestedSessionIdFromURL()。

        ServletRequest接口提供了访问HTTP请求的各种信息和操作的方法,方便在开发中获取HTTP请求的相关参数和属性。在实际开发中,我们通常会使用HttpServletRequest接口,它继承了ServletRequest接口,并增加了更多HTTP特定的请求和响应信息的方法。

// ServletRequest 主要用于封装HTTP请求的信息,所以想要从请求中获取信息,得从ServletRequest 中去寻找。这点很重要

3、HttpServletRequest 接口

        在 Servlet API 中,定义了一个 HttpServletRequest 接口,它继承自 ServletRequest 接口。HttpServletRequest 专门用于封装 HTTP 请求消息,该接口在ServletRequest接口的基础上增加了许多HTTP特定的方法,以提供更多的HTTP请求和响应相关的信息。

        以下是HttpServletRequest相对于ServletRequest新增的一些方法:

  1. getMethod():返回HTTP请求的方法类型(GET、POST等)。
  2. getPathInfo():返回HTTP请求的路径信息。
  3. getPathTranslated():返回HTTP请求的路径翻译后的信息。
  4. getQueryString():返回HTTP请求的查询字符串。
  5. getContentLength():返回HTTP请求的主体内容长度。
  6. getContentType():返回HTTP请求的主体内容类型。
  7. getServletPath():返回HTTP请求的Servlet路径。
  8. getRequestURI():返回HTTP请求的统一资源标识符(URI)。
  9. getRequestURL():返回HTTP请求的统一资源定位器(URL)。
  10. getProtocol():返回HTTP请求的协议名称和版本号。
  11. getRemoteAddr():返回HTTP请求的客户端IP地址。
  12. getRemoteHost():返回HTTP请求的客户端主机名。
  13. getServerName():返回HTTP请求的服务器名称。
  14. getServerPort():返回HTTP请求的服务器端口号。
  15. getScheme():返回HTTP请求使用的协议名称(http、https等)。
  16. isSecure():返回HTTP请求是否通过安全套接字层(SSL)进行传输。

        ServletRequest接口提供了通用的请求信息的访问方法,而HttpServletRequest接口主要是为了提供更多HTTP特定的请求信息,方便在开发中处理HTTP请求和响应。在实际开发中,我们一般会使用HttpServletRequest接口来访问HTTP请求的相关信息。

        HTTP 请求消息分为请求行请求消息头请求消息体三部分,所以 HttpServletRequest 接口中定义了获取请求行、请求头和请求消息体的相关方法。

(1)从HttpServletRequest获取请求行信息

        HTTP 请求的请求行中包含请求方法、请求资源名、请求路径等信息,HttpServletRequest 接口定义了一系列获取请求行信息的方法,如下表。

返回值类型方法声明描述
StringgetMethod()该方法用于获取 HTTP 请求方式(如 GET、POST 等)。
StringgetRequestURI()该方法用于获取请求行中的资源名称部分,即位于 URL 的主机和端口之后,参数部分之前的部分。
StringgetQueryString()该方法用于获取请求行中的参数部分,也就是 URL 中“?”以后的所有内容。
StringgetContextPath()返回当前 Servlet 所在的应用的名字(上下文)。对于默认(ROOT)上下文中的 Servlet,此方法返回空字符串""。
StringgetServletPath()该方法用于获取 Servlet 所映射的路径。
StringgetRemoteAddr()该方法用于获取客户端的 IP 地址。
StringgetRemoteHost()该方法用于获取客户端的完整主机名,如果无法解析出客户机的完整主机名,则该方法将会返回客户端的 IP 地址。

        为了更好地理解这些方法,下面通过案例演示这些方法的使用。创建一个名为 RequestLine 的 Servlet 类,代码如下:

@WebServlet("/RequestLine")
public class RequestLine extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.println("请求方式:" + request.getMethod() + "<br/>" +
                "客户端的 IP 地址:" + request.getRemoteAddr() + "<br/>" +
                "应用名字(上下文):" + request.getContextPath() + "<br/>" +
                "URI:" + request.getRequestURI() + "<br/>" +
                "请求字符串:" + request.getQueryString() + "<br/>" +
                "Servlet所映射的路径:" + request.getServletPath() + "<br/>" +
                "客户端的完整主机名:" + request.getRemoteHost() + "<br/>"
        );
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

        启动 Tomcat 服务器,在地址栏中输入“http://localhost:8080/web/RequestLine?a=1&b=2”,访问 RequestLine,结果如下图。

(2)从HttpServletRequest 获取请求头信息

        当浏览器发送请求时,需要通过请求头向服务器传递一些附加信息,例如客户端可以接收的数据类型、压缩方式、语言等。为了获取请求头中的信息, HttpServletRequest 接口定义了一系列用于获取 HTTP 请求头字段的方法,如下表所示。

返回值类型方法声明描述
StringgetHeader(String name)该方法用于获取一个指定头字段的值
如果请求消息中包含多个指定名称的头字段,则该方法返回其中第一个头字段的值。
EnumerationgetHeaders(String name)该方法返回指定头字段的所有值的枚举集合
在多数情况下,一个头字段名在请求消息中只出现一次,但有时可能会出现多次。
EnumerationgetHeaderNames()该方法返回请求头中所有头字段的枚举集合。
StringgetContentType()该方法用于获取 Content-Type 头字段的值。
intgetContentLength()该方法用于获取 Content-Length 头字段的值 。
StringgetCharacterEncoding()该方法用于返回请求消息的字符集编码 。

        为了更好地理解这些方法,下面通过案例演示这些方法的使用。创建一个名为 RequestHeader 的 Servlet 类,代码如下:

@WebServlet("/RequestHeader")
public class RequestHeader extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        //获得所有请求头字段的枚举集合
        Enumeration<String> headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            //获得请求头字段的值
            String value = request.getHeader(headers.nextElement());
            writer.write(headers.nextElement() + ":" + value + "<br/>");
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

        启动 Tomcat 服务器,在地址栏中输入“http://localhost:8080/web/RequestHeader”,访问 RequestHeader ,结果如下图。

(3)从HttpServletRequest获取 form 表单的数据

        在实际开发中,我们经常需要获取用户提交的表单数据,例如用户名和密码等。为了方便获取表单中的请求参数,ServletRequest 定义了一系列获取请求参数的方法,如下表所示。

返回值类型方法声明功能描述
String getParameter(String name)返回指定参数名的参数值。
String [ ] getParameterValues (String name)以字符串数组的形式返回指定参数名的所有参数值(HTTP 请求中可以有多个相同参数名的参数)。
Enumeration getParameterNames()以枚举集合的形式返回请求中所有参数名。
Map getParameterMap()用于将请求中的所有参数名和参数值装入一个 Map 对象中返回。

        为了更好地理解这些方法,下面通过案例演示这些方法的使用。在webapp目录下,创建 web_form.html,代码如下。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
</head>
<body>
<form action="/web/RequestParam" method="post">
    <table border="1" width="50%">
        <tr>
            <td colspan="2" align="center">welcome to RequestForm!</td>
        </tr>
        <tr>
            <td>输入姓名</td>
            <td><input type="text" name="username" /></td>
        </tr>
        <tr>
            <td>输入密码</td>
            <td><input type="password" name="password" /></td>
        </tr>
        <tr>
            <td>选择性别</td>
            <td><input type="radio" name="sex" value="male" />男 <input
                    type="radio" name="sex" value="female" />女</td>
        </tr>
        <tr>
            <td>选择使用的语言</td>
            <td><input type="checkbox" name="language" value="JAVA" />JAVA
                <input type="checkbox" name="language" value="C" />C语言 <input
                        type="checkbox" name="language" value="PHP" />PHP <input
                        type="checkbox" name="language" value="Python" />Python</td>
        </tr>
        <tr>
            <td>选择城市</td>
            <td><select name="city">
                <option value="none">--请选择--</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="guangzhou">广州</option>
            </select></td>
        </tr>
        <tr>
            <td colspan="2"><input type="submit" value="提交" /></td>
        </tr>
    </table>
</form>
</body>
</html>

        创建一个名为 RequestParam 的 Servlet 类,代码如下:

@WebServlet("/RequestParam")
public class RequestParam extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        // 获取姓名
        String username = request.getParameter("username");
        // 获取密码
        String password = request.getParameter("password");
        // 获取性别
        String sex = request.getParameter("sex");
        // 获取城市
        String city = request.getParameter("city");
        // 获取语言
        String[] languages = request.getParameterValues("language");
        writer.write("用户名:" + username + "<br/>" + "密码:" + password + "<br/>" + "性别:" + sex + "<br/>" + "城市:" + city
                + "<br/>" + "使用过的语言:" + Arrays.toString(languages) + "<br/>");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        doGet(request, response);
    }
}

        启动 Tomcat 服务器,在地址栏中输入“http://localhost:8080/web/web_form.html”,即可访问 form.html,结果如下图。

        在表单中填写信息后,点击提交,结果如下图:

(4)附:URL和URI的区别

        URL和URI都是用于表示资源定位的字符串,但它们在概念上有一些区别。

        URI(Uniform Resource Identifier,统一资源标识符)是一个标识某个资源的字符串,可以用来唯一地标识一个资源,包括但不限于Web页面、图片、文本文件等。URI包括两个部分:URL和URN。URN(Uniform Resource Name,统一资源名称)是通过名字来标识资源的,而URL(Uniform Resource Locator,统一资源定位符)则是通过地址来标识资源的,即URL是一种特定类型的URI,它通过指定地址来标识特定的资源。例如,"https://www.example.com/index.html"是一个URL,它指定了要访问的资源的地址和协议。

        因此,URL是URI的一个子集,所有的URL都是URI,但不是所有的URI都是URL。URI还可以表示一些没有直接关联到网络资源的抽象概念,例如一个人的名字或者一份文档的版本号。而URL则是用来指定如何访问Web资源的字符串,包括协议、主机名、端口号、路径和查询参数等

4、HttpServletRequest 中文乱码问题

        如果在 form 表单输入框中输入中文,例如在输入姓名时,填写“默认用户”,点击提交后就会出现乱码问题,如下图所示

        根据请求方式的不同,请求一般可以被分为两种:GET 请求POST 请求。这两种请求方式都可能会产生中文乱码问题,下面我们分别对它们产生乱码的原因及其解决方案进行介绍。

(1)POST 请求解决中文乱码问题

        乱码的原因:POST 提交的数据在请求体中,其所使用的编码格式时页面一致(即 utf-8)。request 对象接收到数据之后,会将数据放到 request 缓冲区,缓冲区的默认字符集是 ISO-8859-1(该字符集不支持中文),两者使用的字符集不一致导致乱码。

        解决方案:在获取请求参数之前设置 request 缓冲区字符集为 utf-8 ,代码如下。

//修改request缓冲区的字符集为UTF-8
request.setCharacterEncoding("utf-8");
// 获取用户名
String username = request.getParameter("username");

(2)GET 请求解决中文乱码问题

        乱码的原因:Get 请求将请求数据附加到 URL 后面作为参数,浏览器发送文字时采用的编码格式与页面编码保持一致(utf-8)。如果 Tomcat 没有设置字符集,接收 URL 时默认使用 ISO-8859-1 进行解码,ISO-8859-1 不兼容中文,无法正确解码,导致出现乱码。

需要注意的是,在 Tomcat 8 中已解决了 get 方式提交请求中文乱码的问题,使用 Tomcat 8 及以上版本的同学不必再考虑此问题了,如果您使用的是 Tomcat 7 或更早的版本,出现乱码问题可以使用如下的方案解决。

        解决方案:解决 GET 请求中文乱码问题,有以下 3 种解决方案。

        1) 修改 tomcat/conf/server.xml 中的配置,代码如下。

<Connector port="80" protocol="HTTP/1.1"
         connectionTimeout="20000"
           redirectPort="8443" URIEncoding="UTF-8"/>

        2)使用 URLEncoder 和 URLDecoder 进行编码和解码的操作(逆向编解码)。

//得到TOMCAT通过ISO8859-1解码的字符串
String username = request.getParameter("username");
//对字符串使用ISO8859-1进行编码,得到最初浏览器使用UTF-8编码的字符串
username = URLEncoder.encode(username, "ISO8859-1");
//将使用UTF-8编码的字符串使用UTF-8进行解码,得到正确的字符串
username = URLDecoder.decode(username, "UTF-8");

        3)使用 String 的构造方法:String(byte[] bytes, String charset) ,对字节数组(bytes)按照指定的字符集(charset)进行解码,返回解码后的字符串,解决乱码问题(推荐使用)。

//获取姓名
String username = request.getParameter("username");
//使用String的构造方法解决乱码的问题
username = new String(username.getBytes("ISO-8859-1"),"UTF-8");

        测试程序,接收路径参数为中国时,对参数进行重新转码。

@WebServlet("/RequestParam")
public class RequestParam extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        //获取参数
        String name = request.getParameter("a");
        String value = new String(name.getBytes("ISO-8859-1"), "UTF-8");
        System.out.println(value);
        PrintWriter writer = response.getWriter();
        writer.println("请求方式:" + request.getMethod() + "<br/>" +
                "客户端的 IP 地址:" + request.getRemoteAddr() + "<br/>" +
                "应用名字(上下文):" + request.getContextPath() + "<br/>" +
                "URI:" + request.getRequestURI() + "<br/>" +
                "请求字符串:" + request.getQueryString() + "<br/>" +
                "Servlet所映射的路径:" + request.getServletPath() + "<br/>" +
                "客户端的完整主机名:" + request.getRemoteHost() + "<br/>"
        );
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

        启动 Tomcat 服务器,在地址栏中输入“http://localhost:8080/web/RequestParam?a=中国&b=日本”,结果如下图。

        控制台打印如下:

5、Tomcat 中创建 HttpServletRequest 对象的源码分析

        在 Tomcat 中,HttpServletRequest 对象的创建是由 Catalina 处理请求的核心组件 org.apache.catalina.connector.Connector 负责的。具体来说,当 Connector 接收到客户端请求时,会创建 Request 对象(该对象封装了 HttpServletRequest 对象)并将其传递给 Tomcat 的管道处理器 Pipeline 进行处理。Pipeline 中会将 Request 对象传递给多个阶段的处理器(Valve),在每个阶段中对 Request 对象进行处理并执行相应的操作(如安全认证、过滤器等),最终将 Request 对象传递给对应的 Servlet 进行业务逻辑处理。

        具体创建 HttpServletRequest 对象的源码如下所示:

@Override
public void service(SocketWrapperBase<?> socket) throws IOException {
    // ...
    // 创建 Request 对象并将其封装到 Processor 实例中
    Http11Processor processor = createProcessor();
    processor.assign(socket);
    if (proto.isSSLEnabled() && (socket instanceof SecureNio2Channel)) {
        SecureNio2Channel channel = (SecureNio2Channel) socket;
        SSLEngine engine = proto.getSSLEngine();
        if (engine != null) {
            channel.reset(engine);
        }
    }
    // 将请求交给 Pipeline 处理器进行处理
    pipeline.getFirst().invoke(processor.getRequest(), processor.getResponse());
    // ...
}

        从上述代码中可以看出,当接收到客户端请求时,Tomcat 会通过 createProcessor 方法创建 Http11Processor 实例,并将 SocketWrapperBase 作为参数传递给该实例。在 Http11Processor 中,会调用 createRequest 方法创建 Request 对象,并将 SocketWrapperBase 和 Http11InputBuffer 封装到 Request 对象中。最终,Tomcat 将 Request 对象作为参数传递给 Pipeline 处理器进行处理。在 Pipeline 中,会将 Request 对象传递给多个 Valve 进行处理,最终将 Request 对象传递给对应的 Servlet 进行业务逻辑处理。

6、Servlet 容器在接收到客户端请求时会创建哪些对象?

        在接收到客户端请求时,Servlet 容器会创建以下对象:

  1. HttpServletRequest 对象:封装了客户端请求的信息,包括请求参数、请求头、请求体等信息。
  2. HttpServletResponse 对象:封装了响应信息,包括响应状态码、响应头、响应体等信息。
  3. ServletContext 对象:代表 Servlet 上下文,可以用于在不同 Servlet 之间共享数据。
  4. HttpSession 对象:代表客户端的会话,可以用于在同一客户端多次请求之间共享数据。
  5. ServletConfig 对象:代表 Servlet 的配置信息,包括 Servlet 的初始化参数等信息。
  6. ServletRequest 对象:是 HttpServletRequest 的父接口,定义了通用的请求方法,如获取请求参数等。
  7. ServletResponse 对象:是 HttpServletResponse 的父接口,定义了通用的响应方法,如设置响应头等。

        以上对象都是由 Servlet 容器在接收到客户端请求时创建的,可以在 Servlet 中直接使用。其中,HttpServletRequest 和 HttpServletResponse 对象是每个请求独有的,而 ServletContext 和 HttpSession 对象则是在多个请求之间共享的

        需要注意的是,具体创建对象的方式可能因 Servlet 容器而异。例如,在 Tomcat 中,HttpServletRequest 和 HttpServletResponse 对象是由 Catalina 处理请求的核心组件 org.apache.catalina.connector.Connector 负责创建的,而 ServletContext 和 HttpSession 对象则是由 org.apache.catalina.core.StandardContext 创建的。

  • 11
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值