如何搭建属于自己的服务器(Linux7.6版)
从0搭建属于自己的服务器
最近小伙伴推荐的华为云活动,购买服务器相当的划算,本人也是耗费巨资购买了一台2核4G HECS云服务器。
话不多说,在这里给华为云打一个广子,活动力度还是很不错的。
活动详情见链接:https://kuy8.com/xcGtU
1、购买与搭建
一般个人使用,我觉得2核4G的已经绰绰有余啦,所以本文也是基于这个配置来搭建的(看准最便宜的下手😢)
点击进入详情页,然后选择指定的系统镜像即可完成服务器的初始化工作
初始化需要一点点时间,让子弹飞一会儿,服务器初始化完成之后,我们去控制台可以看到我们刚刚购买的服务器
在控制台出现如上界面,就说明服务器已经搭建完成,接下来让我们看看如何连接到这个远程服务器!
2、通过SSH工具连接
由于我们默认配置的服务器系统是LINUX7.6版本,所以我们通过远程工具对其进行连接需要服务器对外开放22端口号。
我们点击进入服务器详细信息页面,看到安全组的默认开放已经将其开放。
这样我们就可以通过工具对其连接了。
Tips:不晓得密码的话,这边建议直接充值密码,点击右侧更多进行重置密码
现在我们知道了用户名root和密码之后,我们进入工具进行连接
输入公网ip地址,账户名以及密码这些重要信息之后即可进行连接:
连接成功如下所示:
3、搭建Docker容器
对于我个人来说,本人比较喜欢使用docker来配置一些服务,例如MySQL、Nginx、Tomcat等。
具体介绍 👉Docker介绍
具体流程:
(1)yum包更新到最新
sudo yum update
这个过程需要等5~10min,具体看网络情况,出现如下图即表示完成:
(2)安装需要的软件包,yum-util提供yum-config-manager功能,另外两个是devicemapper驱动依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
安装成功如下图所示:
(3)设置yum源为阿里云
这个小操作是为了以后下载镜像可以更快一点!
#3.1设置镜像源 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #3.2 sudo sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
(4)更新并安装Docker-CE
sudo yum makecache fast sudo yum -y install docker-ce
(5)安装完成后查看版本
docker -v
出现如下图所示即表示docker安装成功
(6)开启Docker服务
sudo service docker start # 注意: # 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。 # vim /etc/yum.repos.d/docker-ce.repo # 将[docker-ce-test]下方的enabled=0修改为enabled=1 # # 安装指定版本的Docker-CE: # Step 1: 查找Docker-CE的版本: # yum list docker-ce.x86_64 --showduplicates | sort -r # Loading mirror speeds from cached hostfile # Loaded plugins: branch, fastestmirror, langpacks # docker-ce.x86_64 17.03.1.ce-1.el7.centos docker-ce-stable # docker-ce.x86_64 17.03.1.ce-1.el7.centos @docker-ce-stable # docker-ce.x86_64 17.03.0.ce-1.el7.centos docker-ce-stable # Available Packages # Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos) # sudo yum -y install docker-ce-[VERSION]
运行成功之后,我们再输入命令:docker version
到这里docker就成功的安装了,接下来我们配置一些常用的镜像。
4、Docker下配置Nginx
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器 ,同时也提供了IMAP/POP3/SMTP服务。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好。
详情见👉nginx介绍
# service 命令的用法 $ sudo service docker start # systemctl 命令的用法 $ sudo systemctl start docker
Docker把应用程序及其依赖,打包在 image 文件中。
只有通过 image 文件,才能生成 Docker 容器。
image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。
同一个 image 文件,可以生成多个运行的容器实例。
image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。
# 列出本机的所有 image 文件。 $ sudo docker image ls # 删除 image 文件 $ sudo docker image rm [imageName]
1、部署流程:
- 搜索Nginx镜像
docker search nginx
- 拉取Nginx镜像
docker pull nginx
- 查看镜像名为nginx的镜像
docker images nginx
- 运行镜像,生成容器
# 命令解读: # -d:以后台守护线程运行 # --name:容器命名 # -p 80:80 : 映射端口,容器内部80端口映射到服务器80端口 # nginx :指定的镜像(可以通过docker images 查看) docker run -di --name nginx80 -p 80:80 nginx(镜像ID或者镜像名字都可以)
- 查看容器
docker ps
6. 输入公网ip地址:ip:80
出现如上图欢迎页,即表示nginx部署成功
2、配置文件
- 进入容器内部修改配置文件
# 进入容器内部 docker exec -it nginx /bin/bash # 直接修改配置 vim /etc/nginx/nginx.conf
肯定有些童鞋想问,那么上面的配置文件路径是如何得知的?
通过文件查找命令查(按照名称模糊全局查找文件)
find / -name 'nginx.conf'
这里要注意,因为容器与外界是完全隔离的,使用vim命令请先安装vim:
apt-get update apt-get install -y vim
修改完配置,重新加载nginx:
docker exec -it nginx nginx -s reload
- 容器加载外部配置文件
在外部创建文件夹(用于存放Nginx配置文件)
mkdir -p /home/usr/local/docker-config/nginx/conf mkdir -p /home/usr/local/docker-config/nginx/conf.d mkdir -p /home/usr/local/docker-config/nginx/html mkdir -p /home/usr/local/docker-config/nginx/logs
将容器的配置文件复制到创建好的文件夹中
docker cp nginx:/etc/nginx/nginx.conf /home/usr/local/docker-config/nginx/ docker cp nginx:/etc/nginx/conf.d /home/usr/local/docker-config/nginx/conf/ docker cp nginx:/usr/share/nginx/html/ /home/usr/local/docker-config/nginx/html/ docker cp nginx:/var/log/nginx/ /home/usr/local/docker-config/nginx/logs/
修改配置文件
vim /home/usr/local/docker-config/nginx/conf/nginx.conf
删除容器、镜像
docker ps docker rm -vf nginx docker images docker rmi nginx
运行容器
docker run -di --name nginx80 -p 80:80 -v /home/usr/local/docker-config/nginx/nginx.conf:/etc/nginx/nginx.conf -v /home/usr/local/docker-config/nginx/logs:/var/log/nginx -v /home/usr/local/docker-config/nginx/html:/usr/share/nginx/html -v /home/usr/local/docker-config/nginx/conf:/etc/nginx/conf.d -e TZ=Asia/Shanghai --privileged=true nginx
默认配置文件
#user nobody; #nginx进程,一般数值为cpu核数 worker_processes 1; #错误日志存放目录 #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #进程pid存放位置 #pid logs/nginx.pid; #工作模式及连接数上限 events { #单个后台worker process进程的最大并发链接数 worker_connections 1024; } http { #文件扩展名与类型映射表 include mime.types; #默认文件类型 default_type application/octet-stream; #设置日志模式 #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #nginx访问日志 #access_log logs/access.log main; #开启高效传输模式 sendfile on; #激活tcp_nopush参数可以允许把httpresponse header和文件的开始放在一个文件里发布, 积极的作用是减少网络报文段的数量 #tcp_nopush on; #连接超时时间,单位是秒 #keepalive_timeout 0; keepalive_timeout 65; #开启gzip压缩功能 #gzip on; #基于域名的虚拟主机 server { #监听端口 listen 80; server_name localhost; #编码识别 #charset koi8-r; #日志格式及日志存放路径 #access_log logs/host.access.log main; location / { #站点根目录,即网站程序存放目录 root html; #首页排序 index index.html index.htm; } #错误页面 #error_page 404 /404.html; # 将服务器错误页面重定向到静态页面/50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } #代理PHP脚本到Apache上监听127.0.0.1:80 #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} #将PHP脚本传递到正在监听127.0.0.1:9000的FastCGI服务器 #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} #如果Apache的文档根目录与nginx的根目录一致,则拒绝访问.htaccess文件 #location ~ /\.ht { # deny all; #} } #另一个虚拟主机,混合使用IP、名称和基于端口的配置 #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # 服务的证书 # ssl_certificate cert.pem; # 服务端key # ssl_certificate_key cert.key; # 会话缓存 # ssl_session_cache shared:SSL:1m; # 会话超时时间 # ssl_session_timeout 5m; # #加密算法 # ssl_ciphers HIGH:!aNULL:!MD5; # 启动加密算法 # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
使用中的配置文件(所有ip,域名,路径皆为虚构)
#user nobody; worker_processes 2; error_log logs/error.log; pid logs/nginx.pid; #最大文件打开数(连接),可设置为系统优化后的ulimit -HSn的结果 worker_rlimit_nofile 360000; events { #epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能 use epoll; #单个后台worker process进程的最大并发链接数 worker_connections 100000; #是否串行处理连接 multi_accept off; } http { #文件扩展名与类型映射表 include mime.types; #默认文件类型 default_type application/octet-stream; #设定请求缓存 #户端请求的最大可接受体大小,由行表示 client_max_body_size 50m; #服务器名字的hash表大小 server_names_hash_bucket_size 256; #客户机的请求头设置大小,对于绝大多数请求,1K的缓冲区大小就足够了 client_header_buffer_size 256k; #用来指定客户端请求中较大的消息头的缓存最大数量和大小 large_client_header_buffers 4 256k; #用于配置转发至tomcat后;tomcat获取客户端正式ip #允许重新定义和添加一些将被传输到代理服务器的请求头行。作为值,可以使用文本、变量及其组合。 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Port $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #解决js跨域的问题 #增加头标 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; #指定客户机请求体缓冲区大小。 client_body_buffer_size 256k; #客户机的请求头设置读取超时。 client_header_timeout 3m; #客户机的请求体设置读取超时。 client_body_timeout 3m; #客户端分配响应超时时间。 send_timeout 3m; #访问日志存放路径 access_log no; #客户端连接保持活动的超时时间,在超过这个时间之后服务器会关闭该链接。 keepalive_timeout 0; #修改或隐藏Nginx的版本号 server_tokens off; #虚拟主机配置 server { #listen指令指定所包含的服务器接受的地址和端口。可以只指定地址、端口或服务器名作为地址 listen 80; #e用来指定ip地址或者域名,多个域名之间用空格分开 server_name localhost; #对 "/gzh" 启用反向代理 location /gzh { #根据表达式来更改URI,或者修改字符串。注意重写表达式只对相对路径有效。 #此处是将/gzh以前的地址替换成http://weixin.qq.com/q/xxx rewrite ^ http://weixin.qq.com/q/xxx; } location /test { default_type text/html; return 200 "207_80"; } location / { default_type text/html; #根据规则的执行情况,返回一个状态值给客户端。 return 200 "207_80"; } location /status { #这个模块能够获取Nginx自上次启动以来的工作状态,此模块非核心模块,需要在编译的时候手动添加编译参数 stub_status on; #日志 access_log /usr/local/nginx/logs/status.log; } location /lua{ default_type text/html; content_by_lua_file /usr/local/op/code/test.lua; } location /comm{ default_type text/html; if ( $request_uri ~* /comm/gzhqr ) { content_by_lua_file /usr/local/op/code/redisget.lua; } proxy_pass http://192.168.1.209; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 192.168.88.100:8081; server_name www.cs.cc; default_type 'text/html'; charset utf-8; # 日志级别 error_log logs/error.log info; location /test { default_type text/html; return 200 "207_8081"; } location /luac { default_type text/html; #lua_code_cache off; #$request_uri就是完整url中刨去最前面$host剩下的部分,比如http://www.baidu.com/pan/beta/test1?fid=3的就是/pan/beta/test1?fid=3 #~* /devc/gzhqr表示含有/devc/gzhqr为true if ( $request_uri ~* /devc/test ) { content_by_lua_file /usr/local/op/lualib/tcode/test1.lua; } } location / { root html; index index8081.html index8081.htm; } } server { listen 8085; listen 443 ssl; #填写绑定证书的域名 server_name www.cs.cc; #为服务器启用HTTPS。 #ssl on; ssl_certificate /usr/local/op/nginx/conf/1_www.cs.cc_bundle.crt; ssl_certificate_key /usr/local/op/nginx/conf/2_www.cs.cc.key; ssl_session_timeout 5m; #指令启用所指示的协议。 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #描述了允许的密码。密码以OpenSSL支持的格式分配 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; #要求协议SSLv3和TLSv1服务器密码优先于客户机的密码。 ssl_prefer_server_ciphers on; charset utf-8; resolver 114.114.114.114; #日志级别 error_log logs/error.log info; #网页 location ~/social_security_homepage.html { rewrite ^(.*)$ /socialstop.html break; } #网络资源路径 location /h5/huo/images/ { proxy_pass http://192.168.1.209:3000/images/; } #地址 location /h5/ { proxy_pass http://192.168.1.209:3000/; } #本地路径 location /upload/file/ { root /opt/nci/NCI_DOWN/; } if ($request_uri ~* /wxapp/sign/) { rewrite ^/(.*) http://weixin.qq.com/r/xxx? permanent; } #老管理平台图片的重写 if ($request_uri ~* /download/downLoad.do\?loadFile=/ITCT_Mng/image) { rewrite ^/(.*) https://www.cs.cc/upload/file$argloadFile? permanent; } #管理平台的资源转发 if ($request_uri ~* ^(/PRO_GLPT/)) { rewrite ^/PRO_GLPT/(.*)$ /glpt/$1 last; #没有匹配上返回403 状态码为444(此状态码是非标准的),那么直接关闭此TCP连接 #return code #return code text 因为要带响应内容,因此code不能是具有跳转功能的30x #return code URL 此时URI可以为URI做内部跳转,也可以是具有“http://”或者“https://”等协议的绝对URL,直接返回客户端,而code是30x(301, 302, 303, 307,308) #return URL 此时code默认为302,而URL必须是带“http://”等协议的绝对URL return 403; } location /glpt/ { proxy_pass http://192.168.1.209:8088/PRO_GLPT/; proxy_redirect http:// https://; 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; proxy_next_upstream error timeout invalid_header; } if ($request_uri ~* ^(/REDIS/)) { rewrite ^/REDIS/(.*)$ /redis/$1 last; } location /gitblit { proxy_pass http://192.168.1.209:10101/; proxy_redirect http:// https://; 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; proxy_next_upstream error timeout invalid_header; } location /luac { default_type text/html; #lua_code_cache off; if ( $request_uri ~* /devc/gzhqr ) { content_by_lua_file /usr/local/op/lualib/tcode/gzh_info.lua; #过期时间30天 expires 30d; } } location /comm { default_type text/html; #设置变量 set $lable 0; if ($request_uri ~* /main.*/homeinfo) { set $lable 1; content_by_lua_file /usr/local/op/lualib/tcode/busi/main/main.lua; } proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Port $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.1.207:8089/TKB_COMMON; } #维护中的页面 location =/stoptaking.html { #expires -1; add_header Cache-Control no-store ; index stoptaking.html; } }
到这里在docker中配置nginx就已经完成了
5、Docker下配置tomcat
(1)搜索tomcat镜像
search 语法:
sudo docker search 镜像名称:镜像TAG # 如: 没有加TAG,表示默认搜索的是最新版本的tomcat镜像 $ sudo docker search tomcat # 如:搜索 tomcat 8.5 版本 $ sudo docker search tomcat:8.5
(2)拉取镜像
# 拉取 tomcat镜像 sudo docker pull tomcat # 查看docker所有的镜像 sudo docker image ls
创建容器
# -p表示端口映射 sudo docker run -d -p 9000:8080 --name mytomcat -v /data/my_tomcat:/usr/local/tomcat/webapps tomcat
- docker run 其实是 create 和 start 两个命令的合并
- d 表示后台运行容器,并返回容器ID
- p 8090:8080 表示 将容器的8080端口映射到主机的8090端口,前者是主机访问端口:后者是容器内部端口
- --name 给容器起别名,如 my_tomcat
- tomcat:8.5 表示 镜像名称:镜像TAG,默认最新版可以不加TAG
- -v 表示把容器中的某个文件夹挂载到主机中,格式: -v 主机目录:容器目录
运行成功后如下图所示
(3)进入镜像的方法
有两种方式:
1进入一个正在运行容器的目录
docker ps # 查看正在运行的容器,并得到 容器id # 进入tomcat容器内部 docker exec -it [容器id] /bin/bash # 中间那个是容器id 就是 CONTAINER_ID # -it 表示进入
2run运行容器并进入容器目录
sudo docker run -it -p 8090:8080 tomcat /bin/bash # 运行容器并进入容器目录,但不启动 tomcat
停止运行的容器
docker stop [容器id] # 如 sudo docker stop f96d191f065c
6、Docker下部署MySQL
1、准备工作
已安装Docker、开放了服务器安全组访问规则端口号
2、下载mysql8.0 docker镜像
docker pull mysql:8.0.28
3、查看下载的docker镜像
docker images
4、创建挂载目录
mkdir -p /usr/mysql/conf /usr/mysql/data chmod -R 755 /usr/mysql/
5、创建my.cnf,注意配置文件中的端口号、字符集、时区
vim /usr/mysql/conf/my.cnf
配置信息
[client] #socket = /usr/mysql/mysqld.sock default-character-set = utf8mb4 [mysqld] #pid-file = /var/run/mysqld/mysqld.pid #socket = /var/run/mysqld/mysqld.sock #datadir = /var/lib/mysql #socket = /usr/mysql/mysqld.sock #pid-file = /usr/mysql/mysqld.pid character_set_server = utf8mb4 collation_server = utf8mb4_bin secure-file-priv= NULL # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 # Custom config should go here !includedir /etc/mysql/conf.d/
6、启动镜像
docker run --name mysql8.0 --restart=always -p 3305:3306 -v /usr/local/mysql/data:/var/lib/mysql -v /usr/local/mysql/mysql-files:/var/lib/mysql-files -e MYSQL_ROOT_PASSWORD="123123123" -e TZ=Asia/Shanghai -d mysql:8.0.28 --lower-case-table-names=1
参数解释:
-v : 挂载宿主机目录和 docker容器中的目录,前面是宿主机目录,后面是容器内部目录
-d : 后台运行容器
-p 映射容器端口号和宿主机端口号
-e 环境参数,MYSQL_ROOT_PASSWORD设置root用户的密码
--lower_case_table_names 是否配置忽略表名大小写,1忽略0不忽略
7、修改mysql密码、设置远程访问
进入容器
docker exec -it mysql8.0 /bin/bash
连接mysql
mysql -uroot -p
使用mysql库
$ mysql> use mysql
修改访问主机以及密码等,设置为所有主机可访问
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '新密码';
注意:
这里用了mysql_native_password,mysql8.x版本必须使用这种方式修改密码,否则navicate无法正确连接
刷新
$ mysql> flush privileges;
MySQL5.7版本开启远程访问
mysql> use mysql; mysql> GRANT ALL ON *.* TO root@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
7、Docker下部署Redis
1、拉取镜像
docker pull redis
2、创建容器
docker run -di --name=myredis -p 6379:6379 redis
3、进入容器
docker exec -it myredis /bin/bash
8、安装JDK
例如:我们以jdk17为例,在列表中查看可用的JDK软件包版本,以jdk-17_linux-x64_bin.tar.gz安装包为例,执行以下命令。
mkdir /usr/local/jdk cd /jdk wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz # 解压jdk安装包到jdk目录下 tar -xvf jdk-17_linux-x64_bin.tar.gz
配置环境变量
vi /etc/profile
在底部添加如下信息:
#set java environment JAVA_HOME=/usr/local/jdk/jdk-17.0.6 JRE_HOME=$JAVA_HOME PATH=$JAVA_HOME/bin:$PATH CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JRE_HOME/lib/tools.jar export JAVA_HOME JRE_HOME PATH CLASSPATH
执行以下命令保存并退出。
:wq
执行以下命令使/etc/profile里的配置生效。
source /etc/profile
验证安装。
java -version
回显信息如下所示验证安装jdk成功。
java version "17.0.6" 2023-01-17 LTS Java(TM) SE Runtime Environment (build 17.0.6+9-LTS-190) Java HotSpot(TM) 64-Bit Server VM (build 17.0.6+9-LTS-190, mixed mode, sharing)
到这里完成基于Tomcat快速构建Java Web环境
9、安装宝塔面板
执行以下命令,下载并安装宝塔面板。
yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
一键完成操作系统镜像源的配置。
wget http://mirrors.myhuaweicloud.com/repo/mirrors_source.sh && sh mirrors_source.sh
安装完成后,回显如下信息:
posted on 2023-03-10 16:03 JavaCoderPan 阅读(883) 评论(4) 编辑 收藏 举报
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性