用 XAMPP 搭建反向代理服务器

公网 IP 地址 + 80 端口是稀缺资源。在开发、测试阶段,我们常常需要在一个公网 IP 的 80 端口上,绑定多个 WEB 服务,这些服务可能部署在内网的多台异构服务器上(不同操作系统、不同服务器软件)。

用表格来表达就是:

外网访问 重定向到
http://home.test.com http://127.0.0.1:81
http://img.test.com http://127.0.0.1:82
http://js.test.com http://127.0.0.1:83

在 Linux 下,可以通过 vhost 程序来实现这个需求。在 Windows 下,我们有 XAMPP 和 IIS 两种选择。本文重点介绍 XAMPP 的实现方式。

分别搭建 3 个测试服务器

可以采用这些小工具快速创建测试服务器:

设置 hosts 以便测试

首先要让 3 个域名都指向本机。我们可以直接修改本地 hosts 文件以便测试。这种方式立刻生效,免去申请域名的麻烦。

用提升权限的记事本打开 %windir%\system32\drivers\etc\hosts 文件,加入这段:

127.0.0.1 home.test.com
127.0.0.1 img.test.com
127.0.0.1 js.test.com

这里有个快捷的方法,参见:PowerShell 技能连载 - 编辑“hosts”文件

搭建 XAMPP 环境

请参见 XAMPP 学习路线。只需要其中的 Apache 模块即可。确保 XAMPP 能够正常启动,并能够通过 http://127.0.0.1 访问缺省页面。

设置 XAMPP

编辑 xampp\apache\conf\httpd.conf,将 LoadModule proxy_http_module modules/mod_proxy_http.so 前的 # 号去掉。

编辑 xampp\apache\conf\extra\httpd-vhosts.conf,在尾部添加:

ProxyRequests Off

<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>

<VirtualHost *:80>
    ServerName blog.test.com
    ProxyPass / http://127.0.0.1:81/
    ProxyPassReverse / http://127.0.0.1:81/
</VirtualHost>

<VirtualHost *:80>
    ServerName img.test.com
    ProxyPass / http://127.0.0.1:82/
    ProxyPassReverse / http://127.0.0.1:82/
</VirtualHost>

<VirtualHost *:80>
    ServerName js.test.com
    ProxyPass / http://127.0.0.1:83/
    ProxyPassReverse / http://127.0.0.1:83/
</VirtualHost>

重启 XAMPP 中的 Apache 组件

姊妹篇 - 用 IIS 搭建反向代理服务器

用 IIS 也可以实现相同的功能。

注意有个坑:

%windir%\System32\inetsrv\iis.msc 或通过“这台电脑 - 右键 - 计算机管理” 启动 IIS 管理器,可能看不到 ARR 组件而通过 %windir%\system32\inetsrv\InetMgr.exe 则可以看到。

鸣谢

PowerShell 技能连载 - 修正 ISE 的编码

适用于所有 PowerShell 版本

当您在 ISE 编辑器中运行一个控制台程序时,非标准字符,例如“ä”或“ß”将会显示不正常。要修正 ISE 和隐藏的控制台之间通信的编码,请使用这段代码:

# Repair encoding. This REQUIRES a console app to run first because only
# then will ISE actually create its hidden background console

$null = cmd.exe /c echo
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# Now all is fine

cmd.exe /c echo ÄÖÜäöüß

PowerShell 技能连载 - 使用“打开文件”对话框

适用于 PowerShell 3.0 及以上版本

以下是一个快捷的函数,可以用在 ISE 编辑器和 PowerShell 控制台中(适用于 PowerShell 3.0 及以上版本):Show-OpenFileDialog

function Show-OpenFileDialog
{
  param
  (
    $StartFolder = [Environment]::GetFolderPath('MyDocuments'),

    $Title = 'Open what?',

    $Filter = 'All|*.*|Scripts|*.ps1|Texts|*.txt|Logs|*.log'
  )


  Add-Type -AssemblyName PresentationFramework

  $dialog = New-Object -TypeName Microsoft.Win32.OpenFileDialog


  $dialog.Title = $Title
  $dialog.InitialDirectory = $StartFolder
  $dialog.Filter = $Filter


  $resultat = $dialog.ShowDialog()
  if ($resultat -eq $true)
  {
    $dialog.FileName
  }
}

这个函数将打开一个“打开文件”对话框。用户可以选择一个文件,并且选择的文件对象将返回给 PowerShell。所以下次您的脚本需要打开一个 CSV 文件时,您可能就能用上。

PowerShell 技能连载 - 用 Group-Object 来创建哈希表

适用于所有 PowerShell 版本

Group-Object 能把对象输送到管道中,然后在一个管道中把属性相同的对象排在一起。

这个功能十分有用,特别是当您用 Group-Object 来返回哈希表时。它将生成一个按服务状态分组的哈希表:

$hash = Get-Service |
  Group-Object -Property Status -AsHashTable -AsString

您现在可以通过这种方式获取所有正在运行(或已停止的)服务:

$hash.Running
$hash.Stopped

可以用任何想要的属性来分组。这个例子将用三个组来分组文件:一组为小文件,一个组为中等文件,另一个组位大文件。

$code =
{
  if ($_.Length -gt 1MB)
  {'huge'}
  elseif ($_.Length -gt 10KB)
  {'average'}
  else
  {'tiny'}
}

$hash = Get-ChildItem -Path c:\windows |
  Group-Object -Property $code -AsHashTable -AsString


#$hash.Tiny
$hash.Huge

PowerShell 技能连载 - 用 PowerShell 来励志

适用于所有 PowerShell 版本

编写 PowerShell 代码是十分带劲的,但是某些时候会令人感到沮丧。这是一个用 PowerShell 来励志的函数。只需要打开音箱,PowerShell 会在您执行每一条命令之后鼓励你。

function prompt
{
  $text = 'You are great!', 'Hero!', 'What a checker you are.', 'Champ, well done!', 'Man, you are good!', 'Guru stuff I would say.', 'You are magic!'
  'PS> '
  $host.UI.RawUI.WindowTitle = Get-Location
  (New-Object -ComObject Sapi.SpVoice).Speak(($text | Get-Random))
}

PowerShell 技能连载 - 记录脚本做了什么事

适用于所有 PowerShell 版本

您应该知道在 PowerShell 控制台(不是 ISE 编辑器)中,您可以打开记录功能:

PS> Start-Transcript

这将会把所有键入的命令以及所有的命令执行结果都记录到一个文件中。不幸的是,当您运行一个脚本的时候,作用就受限了,因为您无法看到实际的脚本命令。

以下是一个激进的技巧,能够记录包括所有脚本中执行的命令。在您尝试这个技巧之前,请注意这将增加您的日志文件大小并且会导致脚本执行变慢,因为在循环体中,每一次循环都会被记录下来。

只要执行这行代码就可以打开脚本命令记录了:

PS> Set-PSDebug -Trace 1

用 PowerShell 生成随机身份信息

在开发、运维等工作中,我们常常需要生成一些随机的身份信息,例如“张三”、“李四”……等。实际中不光需要姓名,最好还有邮箱、QQ、联系电话、身份证号等。我们可以一劳永逸地写一个 PowerShell 脚本,随时优雅地生成一大串随机身份信息,取之不尽用之不竭。使用效果如下(当然也可以用 Export-Csv 轻松导出到 Excel 或者用 ConvertTo-Html 生成网页):

根据 *PowerShell 技术交流 QQ 群今天的讨论,以及 shrekzpowershell 生成随机用户信息,我做了一些改进。增加了生日、性别、身份证号等。设计要点如下:

  • QQ 号和邮箱须对应。
    身份证号的第 1-6 位是地区号码,应符合 G​B​T​2​2​6​0​—​1​9​9​9 规范。
  • 身份证号的第 7-13 位是生日号码,不能和同一个人的生日号码矛盾。
  • 身份证号的第 17 位,对于男性是奇数,对于女性是偶数,不能和同一个人的性别矛盾。
  • 身份证号的第 18 位是校验位,根据 ISO 7064:1983.MOD 11-2 规范计算。
  • 生成身份证号时,既可以指定生日号码和性别,也可以随机生成。

以下是一个可重用的模块 Get-Identity.psm1,可以把它保存在 %PSModulePath% 目录中,随时调用:

$firstNames = (@'
赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章
云苏潘葛奚范彭郎鲁韦昌马苗凤花方俞任袁柳酆鲍史唐费廉岑薛雷贺倪汤滕殷罗毕郝邬安常
乐于时傅皮卞齐康伍余元卜顾孟平黄和穆萧尹
'@.Split(("`n", "`r")) -join $null).ToCharArray()

$secondNames = (@'
一丁三专世业丝中丰临丹丽举乃义乐乔书云亘亮人仁今仙令仪伟伯伶佑作佩佳侠侬俊俏俐信
修倩健偲儿允元兆光兰兴其典军冠冬冰凌凝凡凯刚初利力勃勇勋化北千卉华卓博卫卿厚原友
双发叡可叶司合吉同名向君吟听启周和咏咸品哲唱善喆喜嗣嘉囡国圣坚基堂墨壁夏多天奇奕
奥好如妃妍妙妞妮姗姝姣娅娇娜娟娥娴婉婧婵婷媚媛嫒嫔嫚子存孟季学宁宇安宜宝实宣宵家
宸容宾密寒寰寻寿小尘尚尹展山岑岚峯峰峻巍州工巧布帅帆希干平年广庆康庸延建弘强弼彤
彦彩彬彭影微德心志忠念忻怀思怡恩恬恺悟悦情惜惠愉意慈慕慧懋懿成才扬承抒拔振捷掣敏
教文斌斯新方施旎旭旻昂昊昌明易昕星春昶晋晓晔晖晤晨景晴晶智暄暖暮曜曦曲曼曾月朋朔
朗望朝木本朵杉杏材杰松林枝枫柏柔柳栋树格桃桐梅梓梦棠森楚楠欢欣歆歌正武毅民水永江
池沈沉沙沛河泉波泰泽洁洛津洮洲流济浓浦浩海涉涛润涵淑淳淼清渊温湃湉湘源溥溪滢滨漪
漫澄澍澹濮濯瀚灵灿炎炳烁烨焕焱然煜煦熙熠燕爽牧献玄玉玑玛玟玲珉珊珍珑珠珺琅琇琛琦
琨琪琲琳琴琼瑜瑞瑶瑾璇璞瓃甜用甫田甲男画畅略白皎益盼真睿知石碧磊礼祖祥祯祺禄福禧
禾秀秉秋程穆空立章童端竹笑笛筠简箫籁米精素红纬纳纵纶经绢绣绮维罗罡美羡羽翎翔翠翮
翰翼耀聪胜能自致舒舟航良艳艺艾芃芊芝芦芬花芳芸苑苗若英茂范茉茗茜茵荌荣荫莉莎莘莲
莹菁菊菡菱菲萌萍萝萧萱蒙蓉蓓蓝蔓蔚蕊蕙蕴蕾薄薇藉藻虎虹蝶行衣裕西言誉许识诗诚语诺
谊谧谷豪贝贞贤资赋赐赡赫超越跃路轩载辉辰达迈运进远迪逸邈邵郁郎采金鑫铃铄锋锐锦长
闲闵阳阵陶隽雄雅雨雪雯雰霁霓霖霞露青靓靖静韦音韵韶顺颀颖颜飇风飙飞香馨驰驹骄高魁
魄鲲鲸鸣鸾鸿鹍鹏麦默黛齐龙
'@.Split(("`n", "`r")) -join $null).ToCharArray()

$mobilePrefixes = @'
134 135 136 137 138 139 147 150 151 152 157 158 159 182 187 188 147 157 188
130 131 132 155 156 185 186 186 133 153 180 189 189 200 133 150 151 152 153
155 156 157 158 159 130 131 132 133 134 135 136 137 138 139 180 182 185 186
187 188 189 170
'@.Split(("`n", "`r", " "), 'RemoveEmptyEntries')

$cityCodes = @'
410701 341101 130901 130601 331001 230501 370601 659001 450301 120221 620701
341001 210201 510101 130501 320901 520401 510701 623001 450401 650201 420901
360701 620401 510501 542521 620501 232701 530401 611001 340401 321301 520101
320401 430501 653101 460101 220301 640201 610801 440501 450701 533421 429004
522401 532901 532801 130101 652101 445301 320601 410301 140201 530501 632121
511301 210501 152921 140901 330701 410101 350501 621101 350901 652801 652201
210801 440801 341801 500101 371401 411301 341501 141101 371301 440301 522201
231101 510901 330601 450201 350301 150201 220101 440901 411601 371101 320101
632221 330301 622901 130201 140101 131001 430301 610701 640101 450801 360601
131101 650101 440101 210301 632801 360401 231001 320801 530601 610201 210701
632321 360501 440201 512001 542621 370901 320201 220501 230801 220401 110228
430401 451201 340701 542301 130401 360201 410901 620601 150301 150801 140401
451001 532501 370101 440601 321001 411701 321101 654002 451401 410501 220801
350401 330201 522301 130701 420301 445101 420701 421301 211201 511701 420601
'@.Split(("`n", "`r", " "), 'RemoveEmptyEntries')

function Get-RandomName {
    return ($firstNames|Get-Random) +
    (($secondNames|Get-Random -Count ((1,2)|Get-Random)) -join $null)
}

function Get-RandomQQ {
    return [string](Get-Random -Minimum 100000 -Maximum 9999999999)
}

function Get-RandomEMail ($QQ) {
    if ($QQ) {
        return "$QQ@qq.com"
    } else {
        return (Get-RandomQQ) + '@qq.com'
    }
}

function Get-RandomMobile {
    return ($mobilePrefixes | Get-Random) +
    ((0..9 | Get-Random -count 8) -join $null)
}

function Get-RandomSex {
    return ('男', '女' | Get-Random)
}

function Get-RandomBirthday {
    return (Get-Date).AddDays(-(Get-Random -Maximum (365 * 110))).Date
}

function Get-RandomID  ([DateTime]$Birthday, $Sex){
    $cityCode = $cityCodes | Get-Random
    #$cityCode = (0..9 | Get-Random -Count 6) -join $null

    if (!$Birthday) {
        $Birthday = Get-RandomBirthday

    }
    $birthdayCode = '{0:yyyyMMdd}' -f $Birthday

    if ($Sex -eq '男' -or $Sex -eq $true) {
        $seq = (Get-Random -Minimum 0 -Maximum 49) * 2 + 1
    } else {
        $seq = (Get-Random -Minimum 0 -Maximum 49) * 2 + 2
    }

    $result = '{0}{1}{2:D3}' -f $cityCode, $birthdayCode, $seq
    $w = @(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
    $total = 0
    for ($i = 0; $i -lt 17; $i++) {
        $total += $w[$i] * [int]::parse($result[$i])
    }
    $checkCode = [string]($total % 11)
    $checkCode = '10X98765432'[$checkCode]

    $result = $result + $checkCode
    return $result
}

function Get-RandomIdentity {
    $qq = Get-RandomQQ
    $birthday = Get-RandomBirthday
    $sex = Get-RandomSex
    return [pscustomobject][ordered]@{
        Name = Get-RandomName;
        QQ = $qq;
        EMail = Get-RandomEMail -QQ $qq;
        Mobile = Get-RandomMobile;
        Birthday = '{0:yyyy/MM/dd}' -f $birthday
        Sex = $sex
        ID = Get-RandomID -Birthday $birthday -Sex $sex
    }
}

Export-ModuleMember *

测试代码 Test-GetIdentity.ps1

if (Get-Module Get-Identity) { Remove-Module Get-Identity }
Import-Module .\Get-Identity.psm1

Get-RandomName # 生成随机的姓名
Get-RandomQQ # 生成随机的 QQ 号
Get-RandomEMail # 生成随机的 e-mail
Get-RandomMobile # 生成随机的手机号
'{0:yyyy/MM/dd}' -f (Get-RandomBirthday) # 生成随机的生日
Get-RandomSex # 生成随机的性别
Get-RandomID # 生成随机的身份证号

Get-RandomIdentity # 生成随机的身份信息

# 批量生成 20 个完整的身份信息
1..20 | % {
    Get-RandomIdentity
} | Out-GridView -Title 随机身份信息

输出结果:

孔懿
9903344437
7351437013@qq.com
15248325719
1950/02/24
男
450301200801030764


Name     : 方盼
QQ       : 8679192225
EMail    : 8679192225@qq.com
Mobile   : 13923186497
Birthday : 2005/11/09
Sex      : 男
ID       : 130101200511090819

以及文章开头显示的那个图形化列表。

您也可以下载完整的 源代码测试脚本

另外如果您对如何提取区域代码感兴趣的话,还可以下载国标行政区划数据 GBT2260-1999.xml 和对应的解析程序 GBT2260.ps1 来研究。

PowerShell 技能连载 - 有趣的声音提示

适用于所有 PowerShell 版本

如果您的计算机装有声卡,那么这段代码可以让您的同事们吓一跳:

function prompt
{
  1..3 | ForEach-Object {
    $frequency = Get-Random -Minimum 400 -Maximum 10000
    $duration = Get-Random -Minimum 100 -Maximum 400
    [Console]::Beep($frequency, $duration)
  }
  'PS> '
  $host.ui.RawUI.WindowTitle = Get-Location
}

这段代码将会缩短您的 PowerShell 提示符,并且在标题栏上显示当前的路径。这还算是有益的功能。搞破坏的部分是每次执行一条命令,都会发出随机频率的刺耳的三连音:)。