Set Java Proxy for Http/Https

本文详细介绍了Java网络编程中使用代理服务器的方法,包括通过命令行参数设置系统属性、使用Proxy类和NTLM认证等技术,以及如何配置不同的网络属性如IPv4/IPv6、代理、缓存等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Command Line JVM Settings

The proxy settings are given to the JVM via command line arguments:

 java -Dhttp.proxyHost=proxyhostURL 
-Dhttp.proxyPort=proxyPortNumber 
-Dhttp.proxyUser=someUserName 
-Dhttp.proxyPassword=somePassword HelloWorldClass

Setting System Properties in Code

Add the following lines in your Java code so that JVM uses the proxy to make HTTP calls. This would, of course, require you to recompile your Java source. (The other methods do not require any recompilation):

 

System.getProperties().put("http.proxyPort", "someProxyPort");
System.getProperties().put("http.proxyUser", "someUserName");
System.getProperties().put("http.proxyPassword", "somePassword");
System.getProperties().put("http.proxyHost", "someProxyURL");

One more configuraiton for Microsoft ISA NTLM Authentication

You need add below in addition is the proxy using NTLM authentication.
-Dhttp.auth.ntlm.domain=DOMAIN

Configuring Authentication Order

There are three authentication mechanisms provided - ntlmdigest & basic in that order by default. It is possible to change the order and also not exclude one or more methods altogether. This can be done with the following property.

-Dhttp.proxyAuth=basic,ntlm

In this example the authentication order will be basic and then ntlm only - digest will not be used.

 

Since Java 1.5 you can also pass a java.net.Proxy instance to the openConnection() method

//Proxy instance, proxy ip = 123.0.0.1 with port 8080
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("123.0.0.1", 8080));
URL url = new URL("http://www.yahoo.com");
HttpURLConnection uc = (HttpURLConnection)url.openConnection(proxy);
uc.connect();
        
String page;
StringBuffer tmp = new StringBuffer();
BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
while ((line = in.readLine()) != null){
   page.append(line + "\n");
}
System.out.println(page);

so you don't need to set system properties. You can use the default PROXY as defined by your networking settings.

System.setProperty("java.net.useSystemProxies", "true");
List l = null;
try {
  l = ProxySelector.getDefault().select(new URI("http://www.yahoo.com"));
}
catch (URISyntaxException e) {
  e.printStackTrace();
}

if (l != null) {
   for (Iterator iter = l.iterator(); iter.hasNext() {
      java.net.Proxy proxy = (java.net.Proxy) iter.next();
      System.out.println("proxy hostname : " + proxy.type());
      InetSocketAddress addr = (InetSocketAddress) proxy.address();
      if (addr == null) {
        System.out.println("No Proxy");
      } 
      else {
        System.out.println("proxy hostname : " + addr.getHostName());
        System.out.println("proxy port : " + addr.getPort());
      }
   }
}

To bypass the PROXY,

URL url = new URL("http://internal.server.local/");
URLConnection conn = url.openConnection(Proxy.NO_PROXY);

Proxy and Username/Password

You might need to identify yourself to the proxy server.

One way is to use the HTTP property "Proxy-Authorization" with a username:password base64 encoded.

System.setProperty("http.proxyHost", "myProxyServer.com");
System.setProperty("http.proxyPort", "80");
URL url=new URL("http://someserver/somepage");
URLConnection uc = url.openConnection ();
String encoded = new String
      (Base64.base64Encode(new String("username:password").getBytes()));
uc.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
uc.connect();
The following example dumps the content of a URL but before we identify ourself to the proxy.
import java.net.*;
import java.io.*;

public class URLUtils {
  public static void main(String s[]) {
    URLUtils.dump("http://www.yahoo.com");
    System.out.println("**************");
    URLUtils.dump("https://www.paypal.com");
    System.out.println("**************");
  }

  public static void dump(String URLName){
    try {
      DataInputStream di = null;
      FileOutputStream fo = null;
      byte [] b = new byte[1];

      // PROXY
      System.setProperty("http.proxyHost","proxy.mydomain.local") ;
      System.setProperty("http.proxyPort", "80") ;

      URL u = new URL(URLName);
      HttpURLConnection con = (HttpURLConnection) u.openConnection();
      //
      // it's not the greatest idea to use a sun.misc.* class
      // Sun strongly advises not to use them since they can
      // change or go away in a future release so beware.
      //
      sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
      String encodedUserPwd =
         encoder.encode("mydomain\\MYUSER:MYPASSWORD".getBytes());
      con.setRequestProperty
         ("Proxy-Authorization", "Basic " + encodedUserPwd);
      // PROXY ----------

      di = new DataInputStream(con.getInputStream());
      while(-1 != di.read(b,0,1)) {
         System.out.print(new String(b));
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}
With JDK1.2, the java.net.Authenticator can be used to send the credentials when needed.
public static void dump(String URLName){
  try {
    DataInputStream di = null;
    FileOutputStream fo = null;
    byte [] b = new byte[1];
 
    // PROXY
    System.setProperty("http.proxyHost","proxy.mydomain.local") ;
    System.setProperty("http.proxyPort", "80") ;
 
    Authenticator.setDefault(new Authenticator() {
      protected PasswordAuthentication getPasswordAuthentication() {
        return new
           PasswordAuthentication("mydomain\\username","password".toCharArray());
    }});
 
    URL u = new URL(URLName);
    HttpURLConnection con = (HttpURLConnection) u.openConnection();
    di = new DataInputStream(con.getInputStream());
    while(-1 != di.read(b,0,1)) {
       System.out.print(new String(b));
    }
  }
  catch (Exception e) {
          e.printStackTrace();
  }
}

Bypass a Proxy

In intranet environment, you may need to bypass the proxy server and go directly to the http server.

The http.nonProxyHosts property indicates the hosts which should be connected too directly and not through the proxy server. The value can be a list of hosts, each seperated by a |, and in addition a wildcard character (*) can be used for matching.

java.exe  -Dhttp.nonProxyHosts="*.mycompany.com|*.mycompany.local|localhost" MyClass

 

Below are  the Networking Properties from http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html

There are a few standard system properties used to alter the mechanisms and behavior of the various classes of the java.net package.
Some are checked only once at startup of the VM, and therefore are best set using the -D option of the java command,
while others have a more dynamic nature and can also be changed using the System.setProperty() API.
The purpose of this document is to list and detail all of these properties.
If there is no special note, a property value is checked every time it is used.

  • IPv4 / IPv6

java.net.preferIPv4Stack (default: false)
If IPv6 is available on the operating system the underlying native socket will be, by default,
an IPv6 socket which lets applications connect to, and accept connections from, both IPv4 and IPv6 hosts.
However, in the case an application would rather use IPv4 only sockets, then this property can be set to true.
The implication is that it will not be possible for the application to communicate with IPv6 only hosts.

java.net.preferIPv6Addresses (default: false)
When dealing with a host which has both IPv4 and IPv6 addresses, and if IPv6 is available on the operating system,
the default behavior is to prefer using IPv4 addresses over IPv6 ones. This is to ensure backward compatibility,
for example applications that depend on the representation of an IPv4 address (e.g. 192.168.1.1).
This property can be set to true to change that preference and use IPv6 addresses over IPv4 ones where possible.

Both of these properties are checked only once, at startup.

  • Proxies

A proxy server allows indirect connection to network services and is used mainly for security (to get through firewalls)
and performance reasons (proxies often do provide caching mechanisms).
The following properties allow for configuration of the various type of proxies.

  • HTTP

The following proxy settings are used by the HTTP protocol handler.

http.proxyHost (default: <none>) The hostname, or address, of the proxy server

http.proxyPort (default: 80) The port number of the proxy server.

http.nonProxyHosts (default: localhost|127.*|[::1])

Indicates the hosts that should be accessed without going through the proxy. Typically this defines internal hosts.
The value of this property is a list of hosts, separated by the '|' character.
In addition the wildcard character '*' can be used for pattern matching.


For example -Dhttp.nonProxyHosts=”*.foo.com|localhost” will indicate that every hosts in the foo.com domain
and the localhost should be accessed directly even if a proxy server is specified.

The default value excludes all common variations of the loopback address.

  • HTTPS

This is HTTP over SSL, a secure version of HTTP mainly used when confidentiality (like on payment sites) is needed.

The following proxy settings are used by the HTTPS protocol handler.

https.proxyHost(default: <none>)
The hostname, or address, of the proxy server

https.proxyPort (default: 443)
The port number of the proxy server.

The HTTPS protocol handler will use the same nonProxyHosts property as the HTTP protocol.

  • FTP

The following proxy settings are used by the FTP protocol handler.

ftp.proxyHost(default: <none>)
The hostname, or address, of the proxy server

ftp.proxyPort (default: 80)
The port number of the proxy server.

ftp.nonProxyHosts (default: localhost|127.*|[::1])
Indicates the hosts that should be accessed without going through the proxy. Typically this defines internal hosts.
The value of this property is a list of hosts, separated by the '|' character. In addition the wildcard character '*' can be
used for pattern matching.

For example -Dftp.nonProxyHosts=”*.foo.com|localhost” will indicate that every hosts in the foo.com
domain and the localhost should be accessed directly even if a proxy server is specified.

The default value excludes all common variations of the loopback address.

  • SOCKS

This is another type of proxy. It allows for lower level type of tunneling since it works at the TCP level.
In effect, in the Java(tm) platform setting a SOCKS proxy server will result in all TCP connections to go through that proxy,
unless other proxies are specified. If SOCKS is supported by a Java SE implementation, the following properties will be used:

socksProxyHost (default: <none>)
The hostname, or address, of the proxy server.

socksProxyPort (default: 1080)
The port number of the proxy server.

socksProxyVersion (default: 5)
The version of the SOCKS protocol supported by the server. The default is 5 indicating SOCKS V5, alternatively 4 can be specified for SOCKS V4.
Setting the property to values other than these leads to unspecified behavior.

java.net.socks.username (default: <none>)
Username to use if the SOCKSv5 server asks for authentication and no java.net.Authenticator instance was found.

java.net.socks.password (default: <none>)
Password to use if the SOCKSv5 server asks for authentication and no java.net.Authenticator instance was found.

Note that if no authentication is provided with either the above properties or an Authenticator, and the proxy requires one,
then the user.name property will be used with no password.

java.net.useSystemProxies (default: false)
On recent Windows systems and on Gnome 2.x systems it is possible to tell the java.net stack, setting this property to true,
to use the system proxy settings (both these systems let you set proxies globally through their user interface).
Note that this property is checked only once at startup.

  • Misc HTTP properties

http.agent (default: “Java/<version>”)
Defines the string sent in the User-Agent request header in http requests. Note that the string “Java/<version>” will be appended
to the one provided in the property (e.g. if -Dhttp.agent=”foobar” is used, the User-Agent header will contain “foobar Java/1.5.0”
if the version of the VM is 1.5.0). This property is checked only once at startup.

http.keepalive (default: true)
Indicates if persistent connections should be supported. They improve performance by allowing the underlying socket
connection to be reused for multiple http requests. If this is set to true then persistent connections will be requested with HTTP 1.1 servers.

http.maxConnections (default: 5)
If HTTP keepalive is enabled (see above) this value determines the maximum number of idle connections that will be simultaneously kept alive,
per destination.

http.maxRedirects (default: 20)
This integer value determines the maximum number, for a given request, of HTTP redirects that will be automatically followed by the protocol handler.

http.auth.digest.validateServer (default: false)

http.auth.digest.validateProxy (default: false)

http.auth.digest.cnonceRepeat (default: 5)

These 3 properties modify the behavior of the HTTP digest authentication mechanism. Digest authentication
provides a limited ability for the server to authenticate itself to the client (i.e. By proving it knows the user's password).


However not all HTTP servers support this capability and by default it is turned off.
The first two properties can be set to true to enforce this check for authentication with either an origin or proxy server, respectively.

It is usually not necessary to change the third property. It determines how many times a cnonce value is re-used.
This can be useful when the MD5-sess algorithm is being used. Increasing this value reduces the computational overhead
on both client and server by reducing the amount of material that has to be hashed for each HTTP request.

http.auth.ntlm.domain (default: <none>)
NTLM is another authentication scheme. It uses the java.net.Authenticator class to acquire usernames and passwords
when they are needed. However NTLM also needs the NT domain name. There are 3 options for specifying that domain:

Do not specify it. In some environments the domain is actually not required and the application does not have to specify it.

The domain name can be encoded within the username by prefixing the domain name, followed by a back-slash '\' before the username.
With this method existing applications that use the authenticator class do not need to be modified,
as long as users are made aware that this notation must be used.

If a domain name is not specified as in method 2) and these property is defined, then its value will be used a the domain name.
All these properties are checked only once at startup.

  • Address Cache

The java.net package, when doing name resolution, uses an address cache for both security and performance reasons.
Any address resolution attempt, be it forward (name to IP address) or reverse (IP address to name),
will have its result cached, whether it was successful or not, so that subsequent identical requests will not have to access the naming service.
These properties allow for some tuning on how the cache is operating.

networkaddress.cache.ttl (default: see below)


Value is an integer corresponding to the number of seconds successful name lookups will be kept in the cache. A value of -1,
or any other negative value for that matter, indicates a “cache forever” policy, while a value of 0 (zero) means no caching.
The default value is -1 (forever) if a security manager is installed, and implementation specific when no security manager is installed.

networkaddress.cache.negative.ttl (default: 10)


Value is an integer corresponding to the number of seconds an unsuccessful name lookup will be kept in the cache. A value of -1,
or any negative value, means “cache forever”, while a value of 0 (zero) means no caching.

Since these 2 properties are part of the security policy, they are not set by either the -D option or the System.setProperty() API,
instead they are set in the JRE security policy file lib/security/java.security.

 

http://docs.oracle.com/javase/6/docs/technotes/guides/net/properties.html

<think>我们正在使用SpringBoot和Vue实现单点登录(SSO)并结合WebSocket通信。现在用户的问题是:如何在使用SSL和HTTPS的情况下配置Nginx以支持WebSocket长连接,特别是与SpringBoot+Vue实现的单点登录系统结合。关键点:1.Nginx配置SSL(HTTPS)并支持WebSocket代理。2.WebSocket连接需要安全(wss://)。3.单点登录系统通常使用JWT令牌,而WebSocket连接需要携带该令牌进行身份验证。4.配置Nginx作为反向代理,将WebSocket请求转发到后端SpringBoot应用。解决方案步骤:###1.获取SSL证书首先,确保你拥有有效的SSL证书(包括证书文件和私钥文件)。如果没有,可以使用Let'sEncrypt免费获取。###2.Nginx基础SSL配置配置Nginx监听443端口,启用SSL,并指定证书和私钥的位置。###3.WebSocket代理配置为了代理WebSocket连接,需要设置以下头部:-`Upgrade`:设置为`$http_upgrade`,用于将连接升级为WebSocket。-`Connection`:设置为`upgrade`,表示升级连接。同时,由于WebSocket是长连接,我们需要设置合理的超时时间(如`proxy_read_timeout`)。###4.单点登录的考虑在WebSocket连接建立时,前端需要携带JWT令牌(通常放在Header中,如Authorization)。Nginx不需要处理JWT验证,因为验证由后端SpringBoot完成。但是,如果SpringBoot应用部署在多个实例上(集群),则需要注意WebSocket会话的保持问题(本问题暂不涉及集群)。###5.配置示例下面是一个完整的Nginx配置示例,它同时支持:-静态资源(Vue项目)-API代理(转发到SpringBoot后端)-WebSocket代理(转发到SpringBoot的WebSocket端点)```nginx#配置WebSocket代理所需的map块map$http_upgrade$connection_upgrade{defaultupgrade;''close;}#HTTPS服务器配置server{listen443ssl;server_nameyour-domain.com;#修改为你的域名ssl_certificate/path/to/your/fullchain.pem;#SSL证书路径ssl_certificate_key/path/to/your/privkey.key;#私钥路径#SSL优化参数ssl_session_cacheshared:SSL:10m;ssl_session_timeout10m;ssl_ciphersHIGH:!aNULL:!MD5;ssl_prefer_server_cipherson;#静态资源路径(Vue项目)location/{root/path/to/vue/dist;#Vue项目打包后的目录try_files$uri$uri//index.html;}#后端API代理(包括SSO认证)location/api/{proxy_passhttp://springboot-app:8080;#后端SpringBoot地址proxy_set_headerHost$host;proxy_set_headerX-Real-IP$remote_addr;proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;proxy_set_headerX-Forwarded-Proto$scheme;}#WebSocket代理配置location/ws/{proxy_passhttp://springboot-app:8080;#与API相同的后端地址proxy_http_version1.1;proxy_set_headerUpgrade$http_upgrade;proxy_set_headerConnection$connection_upgrade;#使用map变量proxy_set_headerHost$host;proxy_set_headerX-Real-IP$remote_addr;proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;proxy_set_headerX-Forwarded-Proto$scheme;#设置合理的超时时间proxy_read_timeout86400s;#长连接超时时间(1天)proxy_send_timeout60s;}}#HTTP重定向到HTTPS(可选)server{listen80;server_nameyour-domain.com;return301https://$host$request_uri;}```###6.前端Vue配置前端使用WebSocket连接时,应该使用`wss://`协议,并且连接地址为Nginx代理的地址(即`/ws/`路径)。同时,在建立WebSocket连接时,需要携带JWT令牌(通常放在Header中)。在Vue中建立WebSocket连接的示例(使用stomp.js):```javascriptimport{Client}from'@stomp/stompjs';constclient=newClient({brokerURL:'wss://your-domain.com/ws/websocket-endpoint',//通过Nginx代理的WebSocket地址connectHeaders:{Authorization:`Bearer${localStorage.getItem('jwt')}`,//携带JWT},debug:function(str){console.log(str);},reconnectDelay:5000,heartbeatIncoming:4000,heartbeatOutgoing:4000});client.activate();```###7.后端SpringBoot配置确保SpringBoot的WebSocket端点配置为接受WebSocket连接。同时,在WebSocket握手时进行JWT验证(在之前的回答中已经提供过拦截器实现)。###注意事项1.**路径匹配**:Nginx配置中的`location/ws/`匹配以`/ws/`开头的URI,因此后端WebSocket的端点地址应以此路径开头(如`/ws/messages`),或者调整Nginx的配置以匹配实际路径。2.**跨域问题**:由于使用Nginx代理,前端和API在同一域名下,因此不会发生跨域问题。但如果没有使用Nginx代理,需要单独处理跨域。3.**SSL证书更新**:定期更新SSL证书以避免过期。###8.验证配置-检查Nginx配置:`sudonginx-t`-重新加载Nginx:`sudosystemctlreloadnginx`###常见问题解决-**问题1**:WebSocket连接失败,出现`404`错误。**解决**:检查Nginx的`location`路径是否匹配,以及后端WebSocket端点是否正确。-**问题2**:WebSocket连接建立后立即断开。**解决**:检查超时配置(`proxy_read_timeout`)是否合理,以及后端服务是否正常运行。-**问题3**:SSL证书不信任。**解决**:确保证书来自可信机构,且域名匹配。###相关问题根据用户的问题,我们可以提出以下相关问题:§§相关问题§§1.如何为Nginx配置自动更新Let'sEncrypt的SSL证书?2.WebSocket连接在集群环境下如何管理?3.如何在SpringBoot中处理WebSocket连接的JWT过期问题?4.Nginx的WebSocket代理配置中,如何实现负载均衡?---以上配置和步骤能够帮助用户在使用SSL和HTTPS的情况下配置Nginx支持WebSocket长连接,并结合单点登录系统。</think> ### Nginx HTTPS 配置支持 WebSocket 长连接(Spring Boot + Vue SSO 场景) 以下是针对 **Spring Boot + Vue 单点登录系统**的完整 Nginx HTTPS 配置方案,支持 WebSocket 长连接: #### 核心配置(nginx.conf) ```nginx # HTTPS 基础配置 server { listen 443 ssl http2; server_name your-domain.com; # SSL 证书配置 ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers on; # WebSocket 连接头处理(关键配置) map $http_upgrade $connection_upgrade { default upgrade; '' close; } # Vue 前端静态资源 location / { root /var/www/vue-dist; try_files $uri $uri/ /index.html; add_header Cache-Control "no-cache"; } # Spring Boot API 代理 location /api/ { proxy_pass http://springboot-backend:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # WebSocket 关键配置(支持单点登录认证) location /websocket/ { proxy_pass http://springboot-backend:8080; # Spring Boot地址 proxy_http_version 1.1; # WebSocket 升级头 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # SSO 单点登录令牌透传(确保JWT传输) proxy_set_header Authorization $http_authorization; # 客户端信息传递 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 长连接超时设置(建议值) proxy_read_timeout 86400s; # 24小时 proxy_send_timeout 86400s; } } # HTTP 重定向到 HTTPS server { listen 80; server_name your-domain.com; return 301 https://$host$request_uri; } ``` #### 关键配置说明 1. **SSL 配置** 使用标准的 HTTPS 配置,确保浏览器信任证书[^4] 2. **WebSocket 升级头** `proxy_set_header Upgrade $http_upgrade` 和 `proxy_set_header Connection $connection_upgrade` 是启用 WebSocket 代理的核心[^2][^3] 3. **单点登录支持** `proxy_set_header Authorization $http_authorization` 确保 JWT 令牌透传到 Spring Boot 后端,用于 WebSocket 连接时的身份验证[^5] 4. **超时设置** `proxy_read_timeout 86400s` 保持长连接(可根据业务需求调整) 5. **路径匹配** `location /websocket/` 需要与 Vue 前端连接地址保持一致 (示例:Vue 应连接 `wss://your-domain.com/websocket/endpoint`) #### Vue 前端连接示例 ```javascript // 使用加密的 WebSocket (wss://) const socket = new WebSocket( `wss://${location.host}/websocket/chat?token=${localStorage.getItem('jwt')}` ); // 或使用 STOMP(需携带SSO令牌) const client = new Client({ brokerURL: `wss://${location.host}/websocket/stomp`, connectHeaders: { Authorization: `Bearer ${localStorage.getItem('jwt')}` } }); ``` #### Spring Boot 配置要点 1. 使用 `@EnableWebSocketMessageBroker` 启用 WebSocket 2. 在拦截器中验证 JWT: ```java public class AuthChannelInterceptor implements ChannelInterceptor { @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); String token = accessor.getFirstNativeHeader("Authorization"); // JWT验证逻辑 } } ``` #### 常见问题解决 1. **SSL 证书错误** 确保证书完整链配置正确:`ssl_certificate` 应包含中间证书[^1] 2. **WSS 连接失败** 前端必须使用 `wss://` 协议,否则会触发安全限制[^4] 3. **SSO 令牌失效** 实现令牌刷新机制,并在 WebSocket 连接中更新令牌 4. **413 Payload Too Large** 添加配置:`client_max_body_size 10M;` 支持大消息传输
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值