首页 > 解决方案 > 将 NextJs 托管到 IIS

问题描述

再会!

我的同事有一个网站 node.js (next.js),当我们通过控制台构建和启动 (npm run build 和 npm start) 时,他的网站运行良好。

我们将它托管在 Azure VM 中(安装了 Windows Server 2016 IIS、iisnode 和 urlrewrite),我们创建了一个管道,我们能够获取工件(运行构建时的“.next”文件夹)并将其部署到 IIS我们仍然需要手动交互来放置 web.config。下面是web.config

<!-- indicates that the hello.js file is a node.js application 
to be handled by the iisnode module -->

<handlers>
  <add name="iisnode" path="service-worker.js" verb="*" modules="iisnode" />
</handlers>

<!-- use URL rewriting to redirect the entire branch of the URL namespace
to hello.js node.js application; for example, the following URLs will 
all be handled by hello.js:

    http://localhost/node/express/myapp/foo
    http://localhost/node/express/myapp/bar

-->

<rewrite>
  <rules>
    <rule name="AMS" stopProcessing="true">
      <match url=".*" />
      <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
      </conditions>
      <action type="Rewrite" url="/" />
    </rule>
  </rules>
</rewrite> 

但是当我们访问该网站时,它会抛出一个需要提供默认页面的 403 错误。(我在这里迷路了,无法通过 IIS 运行他的网站)

注意:他的另一个网站运行良好(因为它有一个 service-worker.js)。

任何人都有将 Next.JS 部署到 IIS 的经验?提前致谢。

标签: node.jsiisnext.jsiisnode

解决方案


在 /public 文件夹中,创建以下内容web.config以接受来自 /a/b/c 的请求并将它们重写到 / 我们的 NextJs 代码所在的位置。

<?xml version="1.0"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="NextJs Routes" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />                            
                    </conditions>
                    <action type="Rewrite" url="/" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

这样做应该可以让您在 /products 之类的路由上重新加载页面,但 NextJs 将呈现 /,即索引页面,因为这是我们的重写规则告诉它交付的内容。

因此,我们需要创建一个以 NextRouter 作为 prop 的 body 组件,然后将窗口的 url 与路由器的 url 进行比较。如果它们不匹配,我们需要使用router.push().

我正在使用 TypeScript,所以我body.tsx

import * as React from 'react';
import { NextRouter } from 'next/router';

export default class Body extends React.Component<{router : NextRouter}>
{    
    componentDidMount()
    {        
        if (window.location.pathname == this.props.router.pathname) return;
        
        this.props.router.push(global.window.location.pathname);        
    }

    render = () => this.props.children;                
}

然后在 _app.tsx 中,我们只需要将 main Component 包装在 Body Component 中。

import { useRouter } from 'next/router'
import Head from 'next/head';
import Body from '../src/components/elements/body';

function MyApp({ Component, pageProps }) {

    const router = useRouter();        
        
    return (
        <>
            <Head>                
                <title>NextJs on IIS</title>
            </Head>

            <Body router={router}>                                
                <Component {...pageProps} />                                
            </Body>
        </>
    )
}

export default MyApp

运行npm run build,并将 /out 文件夹复制到您的 IIS 服务器。


推荐阅读