apache - 迁移到新服务器后,Perl CGI 每日图片脚本未按预期运行
问题描述
我有一个 perl cgi 脚本,多年来一直在 FreeBSD 5.4 Apache 1.3 网络服务器上完美运行,没有遇到任何问题。这是一天脚本的图片,它从给定目录中随机选择一张图片以包含在服务器端包含的 shtml 页面上
<!--#exec cgi="/cgi-bin/pod/pod.cgi"-->
我最近迁移到 Google Cloud Platform 上的新服务器 - Debian 9 (Stretch)、Apache 2.4。剧本坏了。在设置服务器配置以正确执行 cgi perl 脚本并以 ASCII 格式重新上传脚本后,该脚本再次开始工作,但现在出现异常行为。不是整天显示一个图像(相同的图像),然后在午夜更改图像(所需的行为),现在每次在 Web 浏览器中重新加载页面时都会更改图像。
该脚本使用一个平面文件日志来跟踪源目录中的哪些图像已被使用,并且在目标目录中的所有图像都已使用(登录到 pod.log)之前不会重复显示任何图像。正常工作时,它将每天显示一个新图像(在午夜更改),无论页面是否重新加载,所有用户都将保持不变,直到下一个午夜。
已在脚本注释中指定的必要文件上设置了所有权限。该脚本已以 ASCII 格式上传到服务器(如果以二进制格式上传,则根本不起作用)。该脚本正在显示来自正确目录的图像。但是.....每次刷新页面时,都会加载新图像并将其记录到 pod.log 文件中。
我认为可能会影响脚本的一件事是它在哪里获取脚本的日期/时间函数的时间。当我从 debian 命令提示符输入“日期”命令时,服务器返回了我已将服务器配置为的正确时间 - America/Los_Angeles。但我注意到,当我的网络服务器上的文件被触摸或更改时,它会用 UTC 时间对它们进行时间戳记,即 8 小时后。考虑到 Apache 可能导致不同的时间戳,我尝试在 php.ini 中为 apache2 更改时区。这似乎没有改变任何东西(在 apache2ctl 重新启动之后),所以我想,也许我会将服务器时区更改为 UTC。如果你不能打败他们,就加入他们。对?好吧,所以 debian 命令行中的“日期”命令返回了 UTC 时间。另请注意:网络服务器上的文件仍带有 UTC 时区时间戳。一切看起来都很好!但后来我用这个小宝石检查了 perl/cgi 使用的时间,它以人类可读的格式返回日期和时间......
#!/usr/bin/perl
print "Content-type: text/html\n\n";
@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
print $theTime;
...并且此脚本返回时区 America/Los_Angeles 的时间,而不是 UTC。现在我不知道这种差异是否是导致我的每日脚本中出现错误的原因。但我的猜测,以我非常有限的经验告诉我,这至少是可能的。但就我的技术能力而言,我已经对脚本进行了调试/故障排除。
我需要知道:
- 是什么导致脚本在每次重新加载时返回一张新图片并更新日志文件,而不是在 1 天内保持静态?
- 它是由脚本中的无意(胖手指)错误引起的吗?
- 它是由我的新服务器和/或其配置处理脚本的某种不同方式引起的吗?
- 它是由我在上一段中提到的时间戳/时区问题引起的吗?
- 或者这是我完全错过的东西的结果?
接下来,我将提供脚本的源代码和我的 apache 配置文件。EXAMPLE.COM 应替换为您的域名,无论它出现在哪里,并且文件的路径应根据您的位置进行调整。
#!/usr/bin/perl
##############################################################
# POD (Picture of the Day) Version 1.30
##############################################################
package VAR;
use strict;
##############################################################
# Installation
##############################################################
# 1. Edit path to Perl at top of script (pod.cgi) if it
# differs on your server. Usual and default path it
# [/usr/bin/perl]. However, on some servers it may be
# /usr/local/bin/perl. If in doubt, then refer to a script on
# your server that does work, or ask your web host. Edit
# variables below. Ensure you edit (and save) the script using
# an ASCII editor like Notepad.
#
# 2. Via FTP, create directory on server in CGI-BIN called
# pod. No need to CHMOD - you can leave set to server
# default directory permissions.
#
# 3. Via FTP, create subdirectory in 'pod' directory
# called data and CHMOD 777 (drwxrwxrwx).
#
# 4. FTP upload the pod.cgi script to the 'pod'
# directory in ASCII (text) and CHMOD 755 (rwxr-xr-x). You may
# need to rename the scripts with the .pl extension if your
# server uses the .pl extension for CGI-Perl scripts.
#
# images/ 755 (drwxr-xr-x)
# cgi-bin/pod/
# pod.cgi 755 (rwxr-xr-x)
# data/ 777 (drwxrwxrwx)
#
##############################################################
# Operation
##############################################################
#
# METHOD 1: SSI Method
# ====================
# Call the script via SSI (Server-Side Includes). The image
# is embedded in the page. Insert the following SSI tag in
# the desired page:
#
# <!--#exec cgi="/cgi-bin/pod/pod.cgi"-->
#
# In either case, ensure to replace the cgi-bin/pod/ portion
# of the SSI tag with your path to the script.
#
# If you get the [an error occurred while processing this
# directive] error message or no image / message displays,
# make sure (a) the path to Perl is correct, (b) the script
# was uploaded in ASCII, (c) the script is chmod 755
# (rwxr-xr-x) and (d) the path to the script in the SSI tag
# is correct - if in doubt, then ask your web host. If still
# problematic then try the following:
#
# 1. On most servers, the page with a SSI tag must be named
# with the SHTML extension in order for the server to parse
# and execute the SSI tag. Check the page source. If you
# still see the SSI tag, then it was not parsed. Try
# renaming the page with the SHTML extension. If the SSI tag
# is still not parsed (and still visible), then SSI may not
# be enabled on your server - ask your web host.
#
# 2. Try calling the script directly from the browser. If
# you get a server 500 error, then check your server error
# logs.
#
# 3. You can also try the following SSI tag:
#
# <!--#include virtual="/cgi-bin/pod/pod.cgi"-->
#
# METHOD 1: Non-SSI Method
# ====================
# You can also call the script directly from the browser:
#
# http://www.yourdomain.com/cgi-bin/pod/pod.cgi
#
# The image is NOT embedded, but is instead displayed in a
# script generated HTML page.
##############################################################
# Configuration
##############################################################
# Full (absolute) server directory path of directory holding
# image files for the POD script to draw from. Create this
# directory in advance and upload images (in Binary) to this
# directory. No need to chmod. NO trailing slash at end of
# path.
$VAR::image_dir = "/var/www/EXAMPLE.COM/httpdocs/pod";
# URL of directory holding image files for the POD script to
# draw from. NO trailing slash at end of URL.
$VAR::image_url = "http://www.EXAMPLE.COM/pod";
# Full (absolute) server directory path for script data files
# (pod.log, pod.err). Create this directory in advance and
# chmod (777 or drwxrwxrwx). NO trailing slash at end of path.
$VAR::data_dir = "/var/www/EXAMPLE.COM/httpdocs/pod/data";
# Output template - how POD image (or error message) is
# displayed. Feel free to change the HTML but (1) the MS link
# back MUST be retained and (2) the <%image%> tag MUST be
# retained as the tag is replaced with the image (or error
# message) HTML code.
$VAR::template = qq~
<center>
<table border="1">
<th>
<%image%>
</th>
</table>
</center>
~;
##########################################################################
# Do NOT change or alter the code below!
##########################################################################
eval {
($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1");
require 5.004;
};
if ($@) {
print "Content-type: text/html\n\n";
print "Server Error Message: $@\n";
exit;
}
eval { &main; };
if ($@) { &error ("[Error 01]: $@"); }
exit;
###############################################
# Main
###############################################
sub main {
my ($time, $date) = &get_time_stamp();
my $num;
if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [02]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);
my @match = grep (/^$date/, @entries);
if (@match) {
foreach (@match) {
split (/\|/);
if ($_[0] eq $date) {
$num = $_[1];
last;
}
}
}
}
opendir (DIR, "$VAR::image_dir") || &error ("Error [03]: Cannot open $VAR::image - $!");
my @files = sort (grep { m/.*\.gif|.jpg/ } readdir (DIR));
closedir (DIR);
if ($num eq "") { $num = int (rand @files); }
my $image = @files[$num];
if (! -e "$VAR::image_dir/$image") { &error ("Error [04]: Cannot find image file [$image]"); }
my $tag = "<img src=\"$VAR::image_url/$image\">";
$VAR::template =~ s/<%image%>/$tag/gis;
print $VAR::template;
my ($found, $newfile);
if (-e "$VAR::data_dir/pod.log") {
open (LOG, "$VAR::data_dir/pod.log") ||
&error ("Error [05]: Cannot open pod.log file - $!");
my @entries = <LOG>;
close (LOG);
chomp (@entries);
foreach (@entries) {
split (/\|/);
if ($_[0] eq $date) {
$_[2]++;
$newfile .= "$date|$_[1]|$_[2]|$_[3]\n";
$found++;
}
else { $newfile .= "$_\n"; }
}
if (! $found) { $newfile .= "$date|$num|1|$image\n"; }
open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [06]: Cannot open pod.log file - $!");
flock (LOG, 2) || &error ("Error [07]: Cannot lock pod.log file - $!");
print LOG $newfile;
close (LOG);
}
else {
open (LOG, ">$VAR::data_dir/pod.log") ||
&error ("Error [08]: Cannot open pod.log file - $!");
print LOG "$date|$num|1|$image\n";
close (LOG);
chmod (0666, "$VAR::data_dir/pod.log") ||
&error ("Error [09]: Cannot chmod pod.log file - $!");
}
}
###############################################
# Get Time Stamp
###############################################
sub get_time_stamp {
my (@tb) = localtime (time);
my ($ap) = "am";
$tb[4]++;
for (0..4) { $tb[$_] = sprintf ("%02d", $tb[$_]); }
$tb[5] += 1900;
$ap = "pm" if ($tb[2] >= 12);
$tb[2] -= 12 if ($tb[2] > 12);
my $date = "$tb[4]/$tb[3]/$tb[5]";
return ("$tb[2]:$tb[1]:$tb[0]$ap $date", $date);
}
###############################################
# Error Handler
###############################################
sub error {
my $error = shift;
my ($time, $date) = &get_time_stamp();
my $tag = "Cannot display image";
$VAR::template =~ s/<%image%>/$tag/gis;
print $VAR::template;
open (ERR, ">>$VAR::data_dir/pod.err");
print ERR "$time | $ENV{'REMOTE_ADDR'} | $error\n";
close (ERR);
chmod (0666, "$VAR::data_dir/pod.err");
exit;
}
########################################
#end of Picture of the Day script
########################################
这是我的 apache2.conf (同样,无论我的域名出现在哪里,我都将我的域名更改为EXAMPLE.COM......
# configuration directives that give the server its instructions.
# See http://httpd.apache.org/docs/2.4/ for detailed information about
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
# hints.
#
#
# Summary of how the Apache 2 configuration works in Debian:
# The Apache 2 web server configuration in Debian is quite different to
# upstream's suggested way to configure the web server. This is because Debian's
# default Apache2 installation attempts to make adding and removing modules,
# virtual hosts, and extra configuration directives as flexible as possible, in
# order to make automating the changes and administering the server as easy as
# possible.
# It is split into several files forming the configuration hierarchy outlined
# below, all located in the /etc/apache2/ directory:
#
# /etc/apache2/
# |-- apache2.conf
# | `-- ports.conf
# |-- mods-enabled
# | |-- *.load
# | `-- *.conf
# |-- conf-enabled
# | `-- *.conf
# `-- sites-enabled
# `-- *.conf
#
#
# * apache2.conf is the main configuration file (this file). It puts the pieces
# together by including all remaining configuration files when starting up the
# web server.
#
# * ports.conf is always included from the main configuration file. It is
# supposed to determine listening ports for incoming connections which can be
# customized anytime.
#
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
# directories contain particular configuration snippets which manage modules,
# global configuration fragments, or virtual host configurations,
# respectively.
#
# They are activated by symlinking available configuration files from their
# respective *-available/ counterparts. These should be managed by using our
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
# their respective man pages for detailed information.
#
# * The binary is called apache2. Due to the use of environment variables, in
# the default configuration, apache2 needs to be started/stopped with
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
# work with the default configuration.
# Global configuration
#
#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# NOTE! If you intend to place this on an NFS (or otherwise network)
# mounted filesystem then please read the Mutex documentation (available
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
# you will save yourself a lot of trouble.
#
# Do NOT add a slash at the end of the directory path.
#
#ServerRoot "/etc/apache2"
# Set timezone for apache
SetEnv TZ America/Los_Angeles
#
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
#
Mutex file:${APACHE_LOCK_DIR} default
#
# The directory where shm and other runtime files will be stored.
#
DefaultRuntimeDir ${APACHE_RUN_DIR}
#
# PidFile: The file in which the server should record its process
# identification number when it starts.
# This needs to be set in /etc/apache2/envvars
#
PidFile ${APACHE_PID_FILE}
#
# Timeout: The number of seconds before receives and sends time out.
#
Timeout 300
#
# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
#
KeepAlive On
#
# MaxKeepAliveRequests: The maximum number of requests to allow
# during a persistent connection. Set to 0 to allow an unlimited amount.
# We recommend you leave this number high, for maximum performance.
#
MaxKeepAliveRequests 500
#
# KeepAliveTimeout: Number of seconds to wait for the next request from the
# same client on the same connection.
#
KeepAliveTimeout 5
# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a <VirtualHost>
# container, error messages relating to that virtual host will be
# logged here. If you *do* define an error logfile for a <VirtualHost>
# container, that host's errors will be logged there and not here.
#
ErrorLog ${APACHE_LOG_DIR}/error.log
#
# LogLevel: Control the severity of messages logged to the error_log.
# Available values: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the log level for particular modules, e.g.
# "LogLevel info ssl:warn"
#
LogLevel warn
# Include module configuration:
IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
# Include list of ports to listen on
Include ports.conf
# Sets the default security model of the Apache2 HTTPD server. It does
# not allow access to the root filesystem outside of /usr/share and /var/www.
# The former is used by web applications packaged in Debian,
# the latter may be used for local directories served by the web server. If
# your system is serving content from a sub-directory in /srv you must allow
# access here, or in any related virtual host.
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
#<Directory /srv/>
# Options Indexes FollowSymLinks
# AllowOverride None
# Require all granted
#</Directory>
# AccessFileName: The name of the file to look for in each directory
# for additional configuration directives. See also the AllowOverride
# directive.
#
AccessFileName .htaccess
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
# Include of directories ignores editors' and dpkg's backup files,
# see README.Debian for details.
# Include generic snippets of statements
IncludeOptional conf-enabled/*.conf
# Include the virtual host configurations:
IncludeOptional sites-enabled/*.conf
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
这是我的虚拟主机的conf...
<VirtualHost *:80>
ServerName EXAMPLE.com
ServerAlias www.EXAMPLE.com
UseCanonicalName Off
ServerAlias EXAMPLE1.com
ServerAlias www.EXAMPLE1.com
ServerAlias EXAMPLE2.com
ServerAlias www.EXAMPLE2.com
ServerAlias EXAMPLE.co.uk
ServerAlias www.EXAMPLE.co.uk
ServerAlias EXAMPLE.net
ServerAlias www.EXAMPLE.net
ServerAlias EXAMPLE3.com
ServerAlias www.EXAMPLE3.com
ServerAdmin EXAMPLEd@gmail.com
DocumentRoot /var/www/EXAMPLE.com/httpdocs
<Directory /var/www/EXAMPLE.com/httpdocs>
Options -Indexes +FollowSymLinks
AllowOverride All
</Directory>
ScriptAlias "/cgi-bin/" "/var/www/EXAMPLE.com/cgi-bin/"
#<Directory "/var/www/EXAMPLE.com/cgi-bin/">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/members/cgi-bin">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
#<Directory "/var/www/EXAMPLE.com/httpdocs/pod">
# Options +ExecCGI
# AddHandler cgi-script .cgi
# AllowOverride All
#</Directory>
Alias "/passwd/" "/var/www/EXAMPLE.com/passwd/"
<IfModule mod_ssl.c>
SSLEngine off
</IfModule>
<Directory /var/www/EXAMPLE.com>
Options +ExecCGI +FollowSymLinks +Includes
AddHandler cgi-script .cgi
AllowOverride All
</Directory>
<Directory /var/www/EXAMPLE.com>
<IfModule sapi_apache2.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
<IfModule mod_php5.c>
php_admin_flag engine on
php_admin_flag safe_mode on
php_admin_value open_basedir "/var/www/EXAMPLE.com/httpdocs:/tmp"
</IfModule>
</Directory>
<Directory /var/www/EXAMPLE.com>
RewriteEngine on
# the following section prevents outside sites from hot-linking photos
# leave this next line in allow empty referrers, remove to disallow empty referrers
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+\.)*XX\.XXX\.XXX\.XXX(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+\.)*EXAMPLE\.com(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+\.)*EXAMPLE\.org(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+\.)*EXAMPLE\.net(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+\.)*EXAMPLE\.co.uk(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?([a-z0-9-]+\.)*EXAMPLE\.de(:[0-9]+)?(/.*)?$ [NC]
RewriteCond %{HTTP_REFERER} !^http://(.*@)?1\.2\.3\.4(:[0-9]+)?(/.*)?$
RewriteRule .*\.(gif|jpeg|jpg)$ - [NC,F,L]
</Directory>
ErrorLog ${APACHE_LOG_DIR}/EXAMPLE.com-error.log
CustomLog ${APACHE_LOG_DIR}/EXAMPLE.com-access.log combined
# sends 404-not-found errors to error page
ErrorDocument 404 /404-error-page.html
# makes server side includes work on all html pages
AddType text/html .shtml .html .htm
AddHandler server-parsed .shtml .html .htm
RewriteEngine On
# If the hostname is NOT www.domain.com
# RewriteCond %{HTTP_HOST} !^www\.EXAMPLE\.com$
# 301 redirect to the same resource on www.EXAMPLE.com
# RewriteRule (.*) http://www.EXAMPLE.com$1 [L,R=301]
# sets the web surfer's browser to cache images, style sheets, and JavaScript for a week
<IfModule mod_headers.c>
# WEEK
<FilesMatch "\.(jpg|jpeg|png|gif|swf|js|css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
</IfModule>
</VirtualHost>
任何人都可以给我的任何帮助将不胜感激!你们为帮助像我这样的其他初出茅庐的程序员所做的一切令人惊叹。谢谢你,谢谢你,谢谢你。
解决方案
在 Perl 5.12 之前,在 void 上下文中调用时split
将其结果存储在其中。@_
这是一种可怕的做法,因此在 5.12 中删除了“功能”,并添加了警告 ( Useless use of split in void context
)。
我怀疑您使用的 Perl 版本比您以前使用的要新,它split
在 void 上下文中没有特别的行为。如果是这种情况,您应该收到警告。一直用use strict; use warnings qw( all );
!
要解决问题,请更换
split (/\|/);
和
@_ = split (/\|/);
(您应该使用与 不同的数组@_
,但以上是最小的变化。)
您似乎在这方面花了很多时间,但实际上并没有花任何时间尝试调试问题!您所做的第一件事是添加 missing use warnings qw( all );
,这会立即发现问题。即使没有这个,最少的工作也应该将问题缩小到split
.
- 你应该发现这
$num eq ""
总是正确的。 - 这会让你发现那
$_[0] eq $date
总是错误的。 - 这会导致您发现
$_[0]
永远不会设置。
推荐阅读
- evernote - 印象笔记速率限制
- javascript - 在 Web 浏览器控制台中自省 ECMAScript 6 模块成员
- python - Pygame:如何将分离轴定理(SAT)应用于旋转正方形?
- jquery - 设置动态表中下拉菜单的值
- angular - 尽管在 url 中捕获了正确的值,但 Angular 9 组件不会更改页面
- python - Anaconda env 说没有安装 python
- android - 使用 Tablayout 和 ViewPager2 样式特定选项卡
- asp.net-core - Swagger UI - 未知类型:整数问题
- python - Python 3.7 变量链式方法调用
- azure - How can I debug oauth2_proxy when connecting to Azure B2C?