详解Tomcat核心配置、http协议

Java资料站

共 14704字,需浏览 30分钟

 ·

2021-05-19 02:38

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

  作者 |  gonghr 

来源 |  urlify.cn/BJ7baq

1、Tomcat服务器

1.1Tomcat配置与部署(IDEA)

https://www.cnblogs.com/gonghr/p/14731266.html


1.2Tomcat手工创建和打包第一个Web工程

在apache-tomcat-9.0.30目录下的webapps文件夹下新建工程目录起名为MyWeb

 MyWeb中编写html文件

 打开Tomcat后,进入浏览器,输入http://localhost:8080/MyWeb/welcome.html进入网页,第一个网页就部署好了

 如果想要只输入http://localhost:8080/MyWeb就能进入欢迎界面,则需要在MyWeb目录下新建WEB-INF文件夹,在该文件夹下新建web.xml的配置文件

(注意这里的WEB-INF和web.xml的写法是固定的,是Tomcat的标准,不能乱写)

在web.xml中编写配置信息

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

  version="4.0">
  
    <welcome-file-list>
        <welcome-file>welcome.html</welcome-file>   <!--添加欢迎页面-->
    </welcome-file-list>
    
 </web-app>

这样就可以了

1.3在命令行打war包

在web项目的目录下打开命令行,输入 jar cvf E:\DevTols\apache-tomcat-9.0.30\webapps\MyWeb.war . (注意最后是一个空格和一个点)

E:\DevTols\apache-tomcat-9.0.30\webapps\MyWeb.war是war包的目标存储位置和名称

如果把MyWeb的文件夹删除,把打好的war包放在webapps目录下,重新启动Tomcat后,war包会自动解压成文件夹。


1.4解读server.xml

核心代码

<Host name="localhost"  appBase="webapps"
   unpackWARs="true" autoDeploy="true">
</Host>

    name:主机名,及域名。

appBase:主机指定的目录

unpackWARs:是否自动解压war包。若为true则自动解压

autoDeploy:在服务器运行状态下,将一个项目放入当前目录,是否自动部署到服务器,由Tomcat来管理。若为true,则自动部署。

例子:

将war包移到webapps目录以外,并将webapps内原项目文件夹删除,打开Tomcat服务器,将war包移入webapps内则可以看到war包自动解压并被部署到服务器上。

 1.5Tomcat核心结构


Host为访问的主机域名,Host中的Context为主机中的应用名称。若要连接主机,则需要通过连接器Connector。主机的运行基于服务引擎Engine所构建的运行环境。一个服务器Server可以提供多种服务Service。


1.6创建虚拟目录

  • 第一种方式:在主机配置中添加Context标签(不推荐)

将项目目录放到任意一个位置,比如E盘下。

在主机下添加一个应用,在server.xml中添加应用

<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Context path="/xxx" docBase="E:/MyWeb"/>    <!--path是随便写的一个访问路径,docBase是项目在本地的路径-->
</Host>


重启Tomcat,即可访问

但是这个方法重启了服务器,这在大型的项目中是不可能的,重启服务器会造成巨额损失。所以不要使用这种方法!

  • 二种方法:在主机目录中添加配置

Tomcat启动后,会在安装目录的conf中自动创建一个 目录,该目录与server.xml的<Engine/>标签对应,目录名与该标签的name属性相同,默认为Catalina.

该目录为引擎目录。打开可以看到localhost主机目录。

在localhost主机目录中新建一个xml文件,任意名称即可,配置应用信息。

<?xml version="1.0" ?>
<Context docBase="E:/MyWeb"/>


不需重启服务器即可访问


1.7创建虚拟主机

DNS(Domain Name Service) 域名解析服务:将域名与ip地址建立映射。目的是为了方便访问。

比如百度的域名是www.baidu.com  ,而百度的ip用ping www.baidu.com得到是104.193.88.77。怎么可能去记住ip地址,所以域名就是ip的别名,方便好记,利于人们访问。

本机的域名是localhost,ip是127.0.0.1

C:\Windows\System32\drivers\etc\hosts在此路径下可以查看本机ip和域名

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#    127.0.0.1       localhost
#    ::1             localhost 

第一步:创建存放应用的目录

第二部:修改server.xml

在server.xml文件中添加主机,在原Host标签后面添加<Host>标签

<Host name="www.hahaha.com"  appBase="E://web"
            unpackWARs="true"  autoDeploy="true">
</Host>

第三步:修改Host文件

打开C:\Windows\System32\drivers\etc\下的hosts文件,在最后添加

127.0.0.1      www.hahaha.com

注意hosts文件是无法直接修改的,会让另存为。

解决方案一:复制hosts到其他目录,修改完后再复制回去替换原文件。

解决方案二:用notepad++以管理员身份打开。

第四步:

重启服务器,打开网址。

Catalina目录下自动配置了主机



1.8修改默认主机

再考虑一个问题,hosts中本机ip地址127.0.0.1的映射有两个,如果用ip地址访问的话,会访问哪个域名映射呢?

这时发现在server.xml配置文件中明确了默认的主机

    <Engine name="Catalina" defaultHost="localhost">

可以通过修改server.xml文件的defaultHost来修改127.0.0.1的默认域名。


1.9修改默认端口号

还有一个问题,每次访问都要写端口号8080很烦啊,如何才能不写端口号就能访问呢?

还是server.xml文件中,将port修改为80及可,提交请求时不写端口号,浏览器默认端口号是80

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

重启服务器即可

注意可能会出现更改端口号无法访问的情况


1.10解决80端口占用的方法

管理员运行CMD 输入netstat -ano 查看是哪个应用占用了80端口

如图:我的是PID为4的应用占用了80端口 

接着打开任务管理器找到PID为4的应用

这时如果占用80端口的应用不是System的话,看下该应用是否必须要经常用到,否则可以结束任务,

如果和我情况一样占用80端口的是System无法结束任务

这时候就要打开开始菜单找到IIS管理器 

如图点击停止就可以解决80端口被占用的问题了

 

停止之后只需要重启tomcat服务在浏览器上输入http://localhost、就能够看到测试页面了如果绑定了域名同理只需要输入域名就可以访问tomcat的默认访问页面

如图我的修改了端口为80后输入域名显示的页面

1.11配置默认应用

原默认应用是localhost:8080,也就是小猫的界面

apache-tomcat-9.0.30\webapps\ROOT  webapps目录下的ROOT应用是默认应用

如果想在访问localhost:8080的时候打开某个其他的应用,

只要把原来的ROOT随便改个名,把目标应用的名称改为ROOT,重启服务器即可。


1.12批量管理应用

以后的应用名称可能很长,不好输入,那么如何查看一个主机下的所有应用呢?

进入小猫页面,点击右侧的Manage App

会提示输入账号密码

 

点击取消,弹出界面

需要配置conf/tomcat-users.xml文件

在<tomcat-users>标签的最后添加

<role rolename="manager-gui"/>
<user username="1" password="1" roles="manager-gui"/> 

返回小猫界面进入Manager App,左侧为所有应用,点击即可进入,可批量管理。

 


2、HTTP协议

2.1HTTP协议概述


  • HTTP协议概念

HTTP的全称是:Hyper Text Transfer Protocol,意为 超文本传输协议。它指的是服务器和客户端之间交互必须遵循的一问一答的规则。形容这个规则:问答机制、握手机制。

它规范了请求和响应内容的类型和格式。

HTTP协议是由W3C组织管理和维护的。


  • HTTP协议版本

目前HTTP协议主要是1.0版本和1.1版本。这两个版本的区别主要是两个方面。

第一:HTTP1.1版本比1.0版本多了一些消息头。

第二:HTTP1.1版本和1.0版本的执行过程不一样。执行过程如下:

HTTP1.0HTTP1.1
创建连接(TCP/IP)创建连接(TCP/IP)
发送请求发送请求1
得到响应得到响应1
关闭连接发送请求2
创建连接(TCP/IP)得到响应2
发送请求.......
得到响应.......
关闭连接连接超时或手动关闭连接


  • Http1.0版本

HTTP10协议规定,客户端若要向服务端发出请求,必须首先在它们之间创建一个TCP( Transfer Control Protocal,传输控制协议)连接。而当客户端接收到服务端所发出的响应后服务端将关闭TCP连接。只有等待上一次的请求所对应的响应被客户端接收到后,客户端才可发出第二次请求。HTTP1.0协议中的连接属于非持久连接,且服务器不跟踪和记录任何次请求与响应。

 

客户端与服务端每次建立和关闭连接都是一个相对比较费时的过程,会严重影响客户端和服务端的性能。


  • Http2.0版本

HTTP 1.1版本是目前浏览器默认采用的HTTP协议版本,是一种持久连接,在一个TCP连接上可以传送多个HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。一个包含有许多CSS、JS、图片等资源的页面,其所发出的多个请求和响应可以在一个连接中传输。但每个单独的页面文件的请求和响应仍然需要使用各自的连接。
HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。
HTTP1.0在客户端接收到服务端发送来的响应后,TCP连接马上关闭。而HTTP1.1的连接是什么时候关闭呢?客户端在发送创建TCP连接请求之前首先计算出本次连接浏览器所要发送的请求数量,即一次手工请求加上其所携带的所有自动请求数量。当所有浏览器所发出的请求全部发送完毕后,客户端会再自动发送一个关闭TCP连接的请求。这个请求在HttpWatch中是看不到的。
为了防止服务器主动将TCP 连接关闭,在每一个请求中都携带了一个参数Connection用于告诉服务器是否关闭连接。在HttpWatch中可以看到的这些请求中,其Connection参数值均为Keep-Alive保持连接。只有当客户端发送了关闭TCP连接请求时,服务器才会将TCP连接关闭。

 

当然,除了改进了HTTP1.0协议的性能问题外,HTTP 1.1还通过增加更多的请求头和响应头来改进和扩充HTTP 1.0的功能。
例如,由于HTTP 1.0不支持Host 请求头属性,WEB浏览器无法使用主机域名来明确表示要访问服务器上的哪个WEB站点,这样就无法使用wEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。在 HTTP 1.1中增加Host 请求头字段后,WEB浏览器可以使用主机域名来明确表示要访问服务器上的哪个WEB站点,这才实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点。
HTTP 1.1的持续连接,也需要增加新的请求头来帮助实现,例如,Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求的响应后仍然保持连接;Connectio请求头的值为close时,客户端通知服务器关闭连接。

  • Http1.0与Http1.1版本的对比

它们的共同点是请求和响应成对存在,客户端的一次请求一定会对应服务端的一次响应。它们的区别如下:

(1)HTTP1.0
HTTP1.0协议中的连接属于非持久连接,一次TCP连接只能进行一次请求与响应。一次请求与响应对应一个TCP连接。
客户端只有在接收到服务端对上一次请求的响应后,客户端才可发出第二次请求。HTTP1.0不支持对虚拟主机的访问。因为其没有HOST请求头属性,会将用户所发出的域名直接通过DNS转换为IP后,发送到服务端。也就是说,服务端接收到的直接就是个IP而非域名。这样 HTTP1.0的请求就不支持对虚拟主机的访问了。
HTTP1.0协议中在客户端接收到服务端的响应后,马上发送关闭TCP连接的请求,服务端关闭连接。

(2)HTTP1.1
HTTP 1.1支持持久连接,在一个TCP连接上可以传送多个请求和响应。一般情况下,一个页面中的请求与响应对应一个TCP连接。
HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求。HTTP1.1支持对虚拟主机的访问。其在请求头属性中增加了HOST属性,用于记录请求所要访问的虚拟域名。当然,请求中所携带的域名,肯定会通过 DNS将其转换为IP然后查找到相应的主机。但由于请求中还携带有HOST属性,即要访问的域名仍然在请求中,这样的话,服务器就可以从请求中解析出请求所要访问的虚拟主机名。
HTTP1.1协议中在客户端接收到对最后一次请求的响应后,马上发送关闭TCP连接请求,服务端关闭连接。

  • HTTP协议相关说明

HTTP协议概念是客户浏览器和服务器一种一问一答的规则,那么必须要有问有答,而且要先问后答。
但是我们使用
<script>,<link><img>标签,没有手动发起请求,但是仍然能从服务器端拿到数据,原因就是:在浏览器遇到<script>,<link>,<img>标签时会自动发出请求。


2.2HTTP协议组成

由HTTP协议的概念可知,它分为问和答两部分。其中问指的就是请求部分,而答指的就是响应部分。

  • 请求部分

在学习请求协议格式之前,首先要了解两个概念:URL与URI。
URL: Uniform Resource Locator,统一资源定位符。是互联网上标准资源的地址,可以
在全球范围内唯一的确定一个资源
URl: Uniform Resource ldentifier,统一资源标识符,用于标识一个资源的名称。通过这种名称命名的资源可以被互联网定位和访间。

请求行:永远位于请求的第一行
请求消息头:从第二行开始,到第一个空行结束

空白行:用于分离请求报头和请求正文
请求的正文:从第一个空行后开始,到正文的结束

  • 响应部分

响应行:永远位于响应的第一行
响应消息头:从第二行开始,到第一个空行结束

空白行:用于分离响应报头和响应正文
响应的正文:从第一个空行后开始,到正文的结束

  • 消息头的共性分析

消息头名称首字母大写,多个单词每个单词的首字母都大写。
多个单词用-分隔
名称和值之间用冒号加空格分隔
多个值之间用逗号加空格分隔
两个头之间用回车分隔


2.3请求部分详解

  • 请求行详解

请求行:GET /myapp/2.html HTTP/1.1

内容说明
GET请求的方式。(还有POST)
/myapp/2.html请求的资源。
HTTP/1.1使用的协议,及协议的版本。


  • 请求消息头详解


内容说明
Accept告知服务器,客户浏览器所支持的MIME类型。
Accept-Encoding告知服务器,客户浏览器所支持的压缩编码格式。最常用的就是gzip压缩。
Accept-Language告知服务器,客户浏览器所支持的语言。一般都是zh_CN或en_US等。
Referer告知服务器,当前请求的来源。
只有当前请求有来源的时候,才有这个消息头。从地址栏输入的没有来源。
作用:1 投放广告 2 防盗链
Content-Type告知服务器,请求正文的MIME类型。
Content-Length告知服务器,请求正文的长度。
User-Agent浏览器相关信息
Connection: Keep-Alive连接的状态:保持连接
If-Modified-Since告知服务器,客户浏览器缓存文件的最后修改时间。
Cookie(********)会话管理相关,非常的重要。


  • 请求正文详解

第一:只有post请求方式,才有请求的正文。get方式的正文是在地址栏中的。
第二:表单的输入域有name属性的才会被提交。不分get和post的请求方式。
第三:表单的enctype属性取值决定了请求正文的体现形式。概述的含义是:请求正文的MIME编码类型。

enctype取值请求正文体现形式示例
application/x-www-form-urlencodedkey=value&key=valueusername=test&password=1234
multipart/form-data此时变成了多部分表单数据。多部分是靠分隔符分隔的。-----------------------------7df23a16c0210
Content-Disposition: form-data; name="username"

test
-----------------------------7df23a16c0210
Content-Disposition: form-data; name="password"

1234
-----------------------------7df23a16c0210
Content-Disposition: form-data; name="headfile"; filename="C:\Users\zhy\Desktop\请求部分.jpg"
Content-Type: image/pjpeg
-----------------------------7df23a16c0210


2.4响应部分详解

  • 响应行详解

响应行:HTTP/1.1 200 OK

内容说明
HTTP/1.1使用协议的版本。
200响应状态码
OK状态码描述


  • 常用状态码介绍


状态码说明
200一切都OK>
302/307请求重定向(客户端行为,两次请求,地址栏发生改变)
304请求资源未发生变化,使用缓存
404请求资源未找到
500服务器错误

常用的状态码以2、4、5开头,分别表示的意义为:
2xx:表示对请求计算与响应成功。其中常用的状态码是200。
4xx:表示请求错误。其中常见的状态码是404,表示资源找不到。一般都是请求路径
书写有问题。
5xx:表示服务端错误。其中常见的状态码是500,表示服务器内部错误。一般都是服
务端的Java代码发生错误。

  • 响应消息头详解


消息头说明
Location请求重定向的地址,常与302,307配合使用。
Server服务器相关信息。
Content-Type告知客户浏览器,响应正文的MIME类型。
Content-Length告知客户浏览器,响应正文的长度。
Content-Encoding告知客户浏览器,响应正文使用的压缩编码格式。常用的gzip压缩。
Content-Language告知客户浏览器,响应正文的语言。zh_CN或en_US等等。
Content-Disposition告知客户浏览器,以下载的方式打开响应正文。
Refresh定时刷新
Last-Modified服务器资源的最后修改时间。
Set-Cookie(*******)会话管理相关,非常的重要
Expires:-1服务器资源到客户浏览器后的缓存时间
Catch-Control: no-catch不要缓存,//针对http协议1.1版本
Pragma:no-catch不要缓存,//针对http协议1.0版本


  • 响应正文详解

就和我们在浏览器上右键查看源文件看到的内容是一样的。

<html>
    <head>
        <link rel="stylesheet" href="css.css" type="text/css">
        <script type="text/javascript" src="demo.js"></script>
    </head>
    <body>
        <img src="1.jpg" />
    </body>
</html>

  • 指定默认错误页面

当发生诸如404、500错误时,Web容器给出一个英文提示的页面。若系统给出这样的页面,则说明系统设计的界面不友好。
不过,在 web.xml中允许应用指定默认的错误码所对应的错误页面。只要服务端向客户端浏览器发出指定的状态码,则系统就会自动跳转到指定页面。

2.5GET和POST请求方式

  • GET请求

由于GET请求会将请求所携带的参数作为请求URL中的一部分出现,所以请求参数会显示在地址栏。而这就导致了GET提交的三点不足:
1.参数值只能是字符串,而不能是其它类型
2.可以携带的数据量少
3.数据安全性低
但GET请求有一个很重要的特征:客户端一旦接收到“服务器向GET请求发送的响应”后,浏览器会自动缓存响应。当客户再次进行相同请求提交时,将直接读取本地浏览器缓存中数据,而不再向服务端真正发送数据,让用户感觉服务端的响应很快,提升用户体验,减轻了服务器压力。

  • POST请求

POST请求会将请求所携带的数据以请求正文的形式出现,所以与GET方式相比,就显示出了三点长处:
1.数据类型可以是任意类型,还可以是声音、视频、图片等文件
2.请求可以携带的数据量大
3.数据安全性高
但发出 POST请求的客户端浏览器不会对接收到的“服务器向POST 请求发送的响应”进行缓存。
当用户再次进行相同请求时,仍是真正向服务器发送的请求,从服务器读取的数据。

为什么要设计为“GET请求的响应结果会被浏览器缓存,POST请求的响应结果不会被浏览器缓存”呢?主要有两点原因。

一个原因是,以不同的方式提交请求其目的也是不同的。
GET请求的目的一般是客户端要从服务端下载资源,发送相同的请求就代表要下载相同的资源。既然要下载相同的资源而这些资源已经被下载到了客户端,那么就无需再下载了所以也就无需再向服务器发送真正的下载请求了。所以就将GET提交方式设计为了“GET请求的响应结果会被浏览器缓存”。
但POS请求的的一般是客户端要向服务器端上传资源。对于向服务器端上传资源后响应结果,浏览器是无需缓存的。

另一个原因是,是否是相同的请求,两种提交方式的比较难易程度是不同的。
GET提交方式的请求只包含请求行、请求头与空行三部分,请求体为空。所以第二次请求与前一次请求是否相同,浏览器很好做出比较。
但POST提交方式所包含的数据量比较大,主要体现在请求正文内容较多上。请求正文可以是图片、音频、视频等文件,而对第二次请求与前一次请求是否相同的比较,仅从这些内容来看就已经很不好比较了。即对于POST提交,是否是相同请求的提交是不好做出比较的,或者说是无法进行比较的。所以将POST提交方式设计为了“POST请求的响应结果不会被浏览器缓存”。

  • 默认请求提交方式

浏览器向服务器提交请求的方法常见的有五种,这五种方法所采用的提交方式要么是GET方式,要么是POST方式。具体提交方式如下表:

  • 请求提交方式的选择

根据以上叙述,具有以下几种情况之一的,选择POST 提交方式。其它均采用GET提交方式。
1.提交时所携带的数据类型不是字符串
2.提交时所携带的数据量比较大
3.提交时所携带的数据具有敏感性,安全性要求较高

为什么POST提交的安全性就高?

因为能够实现 POST提交的方式只有两种:通过表单的POST提交,与通过AJAX的Post提交。其它方式均为GET提交方式。对于一个提供了POST登录页面的系统,若用户试图通过地址栏等方式进行登录,则说明其一定是非法登录
也就是说,只要我们设置系统的登录请求提交方式是POST,那么就会出现以下两种情况:若用户以POST方式提交登录请求,我们无法判断其是否是非法登录。因为他有可能是通过其它表单的POST方式提交的登录请求。

若用户以GET方式提交登录请求,则马上就可以判断其是非法登录。基于以上原因,POST提交方式的安全性要高于GET提交方式。


3、综合案例-Tomcat的具体应用

3.1静态资源案例-门户类网站的部署和访问

  • 案例介绍

需求:

在浏览器中输入地址,访问静态HTML页面。

细节说明:

HTMLCSS课程中制作的页面加入到JavaWeb工程中,在Tomcat中部署工程,然后启动Tomcat服务器,并使用浏览器访问。

  • 实现步骤

第一步:创建工程并选择使用的Tomcat版本

第二步:拷贝资源到工程的web目录中

第三步:在web.xml中配置默认主页

第四步:部署工程到Tomcat服务器

第五步:测试浏览器访问


3.2动态资源的案例-学生管理系统的部署和访问

  • 案例介绍

需求:

把JavaSE进阶阶段的学生管理系统的服务器改用Tomcat实现。

细节说明:

把学生管理系统涉及的HTML和样式以及图片文件拷贝到JavaWeb工程中,在Tomcat中部署工程,然后启动Tomcat服务器,并使用浏览器访问。

  • 实现步骤

第一步:创建工程

第二步:拷贝资源

第三步:配置默认主页

第四步:部署项目

  • 创建案例中的动态资源-Servlet

       1) Servlet简介

Servlet翻译成中文是服务端脚本,它是SUN公司推出的一套规范,称为Servlet规范。Servlet规范是JavaEE规范中的一部分。我们可以通过查阅JavaEE规范的API来了解Servlet的基本概念。通过点击JavaEE8官方文档,就可以看到关于Servlet的内容介绍。

      2) 按步骤编写Servle

前期准备:在IDEA创建Javaweb工程

第一步:编写一个普通类实现Servlet接口或者继承GenericServlet类或者继承HttpServlet

第二步:重写service方法,输出一句话


第三步:在web.xml配置Servlet

第四步:启动tomcat服务器测试

在地址栏输入:http://localhost:8585/crm/studentServlet 测试访问结果


      3)测试访问








粉丝福利:Java从入门到入土学习路线图

👇👇👇

👆长按上方微信二维码 2 秒


感谢点赞支持下哈 

浏览 43
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报