支持国货自强不息 發表於 2020-9-29 10:38:00

如何在 IIS 上部署 Go API?

<h2 id="问题场景">问题场景</h2>
<p>我这边原先的技术栈主要是 .NET(Core), 所以服务器基本上都是 Windows Server + IIS.</p>
<p>这次有个 API 服务用 Go 重写, 但是部署有点不美, 直接执行黑框框不好看, 也容易丢, 做成服务又不方便更新维护, 想着能不能继续挂载在 IIS 下.</p>
<p>于是乎...</p>
<p>首先想到的是 IIS 下有个 FastCGI 支持, 以前还在 IIS 下部署过 PHP 项目.</p>
<p>搜到 Go 中有个 <code>net/http/fcgi</code> 库, 写个简单服务验证一下, 代码如下:</p>
<pre><code class="language-go">package main

import (
        "net"
        "net/http"
        "net/http/fcgi"
)

func handler(resp http.ResponseWriter, req *http.Request) {
        resp.Write([]byte("hello"))
}

func main() {
        mux := http.NewServeMux()
        mux.HandleFunc("/", handler)

        l, err := net.Listen("tcp", ":0")
        if err != nil{
                panic(err)
        }
        err = fcgi.Serve(l, mux)
        if err != nil{
                panic(err)
        }
}

</code></pre>
<p>执行 <code>go run main.go</code> 命令后, 程序没有任何异常或输出直接就结束了...</p>
<p>资料搜了一圈看到这玩意基本已被遗忘在不知道哪个旮旯里了...</p>
<p>然后搜到 Azure 前些年用HttpPlatformHandler Module 在 IIS 上支持 Java/Node/... 应用程序.</p>
<p>试了下基本也是废了.</p>
<h2 id="解决方案">解决方案</h2>
<p>最后溜达了一圈, 发现 HttpPlatformHandler 已被 ASPNETCore Module 宿主模块取代.</p>
<p>那么就跟我们在 IIS 上部署 ASP.NET Core 应用程序一样, 首先下载并安装 ASP.NET Core Hosting Bundle, 了解更多可参阅 ASP.NET Core Module</p>
<p>然后新建对应的站点, 应用程序池调整成 <strong>无托管代码</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/1279971/202009/1279971-20200929153751424-1431970900.png" alt="" loading="lazy"></p>
<p>IIS 这边已经准备就绪.</p>
<p>来看看我们代码和配置</p>
<pre><code class="language-go">// main.go
package main

import (
        "fmt"
        "net"
        "net/http"
        "os"
)

func handler(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Go running on IIS"))
}

func main() {
        mux := http.NewServeMux()
        mux.HandleFunc("/", handler)

        // 获取由 ACNM 设置的环境变量
        port := "0" // default
        envPort := os.Getenv("ASPNETCORE_PORT")
        if envPort != "" {
                port = envPort
                fmt.Println("get env ASPNETCORE_PORT", port)
        }

        l, err := net.Listen("tcp", ":" + port)
        if err != nil{
                panic(err)
        }
        defer l.Close()
        fmt.Println("listening on", l.Addr().String())
        err = http.Serve(l, mux)
        if err != nil{
                panic(err)
        }
}

</code></pre>
<p>关键点就是代码中要通过获取 ACNM 提供的端口环境变量, 也就是 <code>ASPNETCORE_PORT</code>, 熟悉 ASP.NET Core 的小伙伴对这个应该不陌生了.</p>
<p>然后构建我们的可执行文件 xxx.exe</p>
<pre><code>go build
</code></pre>
<p>然后配置 web.config 内容如下:</p>
<pre><code class="language-xml">&lt;!-- web.config --&gt;
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;configuration&gt;
&lt;location path="." inheritInChildApplications="false"&gt;
    &lt;system.webServer&gt;
      &lt;handlers&gt;
      &lt;add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /&gt;
      &lt;/handlers&gt;
      &lt;aspNetCore processPath=".\your.exe" arguments="" stdoutLogEnabled="true" stdoutLogFile=".\stdout" /&gt;
    &lt;/system.webServer&gt;
&lt;/location&gt;
&lt;/configuration&gt;
</code></pre>
<p>把 <strong>xxx.exe</strong> 和 <strong>web.config</strong> 扔到前面新建的站点中即可.</p>
<p>后续更新升级直接替换 exe 即可.</p>
<p>Go 写的程序体积比较小, 构建后也只有单个执行文件, 清爽多了.</p>
<p><img src="https://img2020.cnblogs.com/blog/1279971/202009/1279971-20200929161735987-1187884920.png" alt="" loading="lazy"></p>
<p>最后来个效果图</p>
<p><img src="https://img2020.cnblogs.com/blog/1279971/202009/1279971-20200929160544445-827744221.png" alt="" loading="lazy"></p>
<h2 id="注意事项">注意事项</h2>
<p>如出现以下错误信息, 可能是端口号已被占用, 换个端口号试试</p>
<pre><code> listen tcp :8080: bind: An attempt was made to access a socket in a way forbidden by its access permissions.
</code></pre>
<h2 id="参考">参考</h2>
<ul>
<li>程序是如何接收并启动监听 IIS 站点设置的端口号的?</li>
<li>ASP.NET Core 中的 Web 服务器实现</li>
<li>在Windows Server 2008上部署Go Web项目</li>
<li>使用 FastCGI 在 IIS 7 上托管 PHP 应用程序</li>
<li>在Go + FastCGI中,使用多个处理程序有意义吗?</li>
<li>Run go web application on IIS</li>
<li>Announcing the Release of the HttpPlatformHandler Module for IIS 8+</li>
<li>Download HttpPlatformHandler v1.2</li>
<li>running-go-behind-iis</li>
</ul>


</div>
<div id="MySignature" role="contentinfo">
    [支持/订阅](https://afdian.com/a/taadis)作者,以获得更多服务.<br><br>
来源:https://www.cnblogs.com/taadis/p/how-to-deploy-go-api-on-iis.html
頁: [1]
查看完整版本: 如何在 IIS 上部署 Go API?