【问题标题】:Deploy Angular Universal to IIS将 Angular Universal 部署到 IIS
【发布时间】:2018-08-08 01:05:06
【问题描述】:

我在web.config 中将 Node.js 部署到 IIS 时遇到问题:

> <handlers>
>         <add name="iisnode-ng-universal" path="dist/server.js" verb="*" modules="iisnode" />
>     </handlers>

 <rule name="ng-universal" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{HTTP_HOST}" pattern="test" />
        </conditions>
        <action type="Rewrite" url="dist/server.js" />
    </rule>

我收到此错误:

image

这是我的网络文件树的样子:

web files

我试图给予IIS_IUSRSIUSR 的完全权限,但它似乎不起作用。就像这篇文章建议的那样: iisnode encountered an error when processing the request

【问题讨论】:

    标签: node.js angular express angular-universal


    【解决方案1】:

    你能试试下面的代码吗..它对我有用

    <?xml version="1.0" encoding="utf-8"?>
    
    
    <configuration>
        <system.webServer>        
          <handlers>
            <add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
          </handlers>
          <rewrite>
            <rules>
                <rule name="DynamicContent">
                     <match url="/*" />
                     <action type="Rewrite" url="server.js"/>
                </rule>
           </rules>
          </rewrite>
        </system.webServer>
      </configuration>
    

    你的 server.js 可以在 dist 文件夹之外。

    【讨论】:

    • 这使iisnode在处理请求时遇到错误。 HRESULT:0x2 HTTP 状态:500 HTTP 子状态:1002 HTTP 原因:内部服务器错误您收到此 HTTP 200 响应,因为 system.webServer/iisnode/@devErrorsEnabled 配置设置为“真”。除了node.exe进程的stdout和stderr的日志,考虑使用debugging和ETW traces来进一步诊断问题。 error.pls 帮我修复它
    • 您好,我遇到了这个错误:HTTP 错误 500.21 - 内部服务器错误处理程序“iisnode”的模块列表中有一个错误的模块“iisnode”知道如何解决吗?
    【解决方案2】:

    如果您想通过服务器端渲染运行 Angular 应用程序:

    1-新建项目:

    ng new anguniversal
    

    2-启用服务器端渲染 (SSR)

    ng add @nguniversal/express-engine
    

    步骤 1

    首先执行下面给出的命令,用 express 服务器构建一个 Angular 应用程序。
    npm run build:ssr
    

    现在您可以在项目文件夹中看到 dist 文件夹。

    第 2 步

    在 Windows 服务器中创建一个新文件夹(例如将其命名为 angular-universal)并从此处的项目文件夹中复制 dist 文件夹

    第三步

    从 dist/anguniversal/server 文件夹复制 main.js 文件并将其直接粘贴到 angular-universal 文件夹中。

    第四步

    创建并打开 Web.config 文件(在 angular-universal 文件夹中)并将代码添加到其中。

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.webServer>
        <handlers>
          <add name="iisnode" path="main.js" verb="*" modules="iisnode" />
        </handlers>
        <rewrite>
          <rules>
            <rule name="DynamicContent">
              <match url="/*" />
              <action type="Rewrite" url="main.js"/>
            </rule>
            <rule name="StaticContent" stopProcessing="true">
              <match url="([\S]+[.](jpg|jpeg|gif|css|png|js|ts|cscc|less|ico|html|map|svg))" />
              <action type="None" />
            </rule>
          </rules>
        </rewrite>
        <staticContent>
          <clientCache cacheControlMode="UseMaxAge" />
          <remove fileExtension=".svg" />
          <remove fileExtension=".eot" />
          <remove fileExtension=".ttf" />
          <remove fileExtension=".woff" />
          <remove fileExtension=".woff2" />
          <remove fileExtension=".otf" />
          <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
          <mimeMap fileExtension=".svg" mimeType="image/svg+xml"  />
          <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
          <mimeMap fileExtension=".woff" mimeType="application/x-woff" />
          <mimeMap fileExtension=".woff2" mimeType="application/x-woff" />
          <mimeMap fileExtension=".otf" mimeType="application/otf" />
        </staticContent>
      </system.webServer>
    </configuration>
    

    第 5 步

    在服务器上安装IIS Node & URL Rewrite

    第 6 步

    在 IIS 中添加网站...。

    第 7 步

    在 IIS 中,转到应用程序池。对于您创建的网站(角度通用)。然后将 .NET CLR 版本更改为无托管代码。

    完成,您可以查看结果。

    【讨论】:

    • 这对我有用,唯一的额外步骤是让 IIS_IUSERS 完全控制您网站的根目录。
    【解决方案3】:

    在将我的 Angular 8 项目升级到 9 之后,我的意思是我几乎将所有东西都升级到了最新版本,发生了几件事。

    1.- webpack.config.js 文件被重命名为 .bak 所以似乎不再使用 webpack 了,事实上如果我尝试重新激活 webpack 构建没有任何反应,它会创建构建但脚本没有不要跑。和node server.js一起跑进进出,什么也没说。

    2.- 现在 dist 文件夹在根目录中没有 .js 文件,并且浏览器和服务器构建的文件夹像以前一样在那里,但甚至编辑 web.config 文件以指示 iisnode 运行 server/main.js 而不是server.js 不管我做什么,总是抛出 500。

    3.- 一开始唯一有效的方法是在本地运行

    npm run dev:ssr
    

    这意味着在浏览器构建中对视图的引用是存在的,但它的运行方式就像它应该从根请求 dist/browser 一样运行。

    我修改了angular.json中的构建路径和服务器构建路径,在./dist文件夹的根目录下创建了main.js文件。

    angular.json(输出路径已修改)

    architect: {
      "build": {
        "builder": "@angular-devkit/build-angular:browser",
        "options": {
          "outputPath": "dist/browser",
          "index": "src/index.html",
          "main": "src/main.ts",
          "tsConfig": "tsconfig.app.json",
          ...
        },
        ...
      },
      "server": {
        "builder": "@angular-devkit/build-angular:server",
        "options": {
          "outputPath": "dist",
          "main": "server.ts",
          "tsConfig": "tsconfig.server.json"
        },
        ...
      },
      ...
    }
    

    好吧,问题来了。浏览器构建生成 ./dist/browser 没有问题,服务器构建确实将 main.js 文件直接放在 ./dist 但不知何故它决定删除 ./dist/browser 文件夹并在运行节点 main.js 时(@987654329 @指点to main.js)它找不到./browser/index.html,当然不是因为服务器构建过程设法删除了浏览器文件夹。

    hacky 解决方案,运行第三次构建(再次构建浏览器)

    我希望这可以解决,但老实说,这根本不会打扰我,计算机运行构建,而不是我,但你知道,如果服务器构建过程不删除它可能会更好更快浏览器构建文件夹。

    现在每次我部署选定的构建时,它都会直接从 AppVeyor 很好地部署到 Azure 应用服务,没有任何问题。

    package.json(注意服务器构建后额外的生产构建)

    {
      ...
      "scripts": {
        ...
        "dev:ssr": "ng run Angular-Universal:serve-ssr",
        "serve:ssr": "node dist/main.js",
        "build:ssr": "npm run build:universal && ng run Angular-Universal:build:production",
        "start:ssr": "npm run build:ssr && npm run serve:ssr",
        "build:universal": "ng run Angular-Universal:build:production && ng run Angular-Universal:server:production",
        "prerender": "ng run Angular-Universal:prerender"
      },
      ...
    }
    

    请注意,build:ssr 脚本正在执行两个构建,然后再次构建浏览器。 另请注意,serve:ssr 脚本已修改为运行 dist/main.js

    最后必须修改 server.ts 文件以根据目标系统的文件夹结构从 ./browser/index.html 或 ./dist/browser/index.html 请求视图。当部署到 Azure 应用服务 main.js 请求 browser/index.html 但如果该项目在我的本地环境中使用 npm run dev:ssrnode main.js 提供并在 macOS 上运行它请求 dist/browser/index.html。反正一个简单的 if 就可以跳过这个障碍。

    server.ts(应用功能的变化)

    // The Express app is exported so that it can be used by serverless Functions.
    export function app() {
      const server = express();
    
      let distFolder: string;
      const path1 = join(process.cwd(), 'browser');         // Running from the deployed version (production)
      const path2 = join(process.cwd(), 'dist/browser');    // Running from the source (macOS local development)
    
      if (fs.existsSync(path1)) {
        distFolder = path1;
      } else if (fs.existsSync(path2)) {
        distFolder = path2;
      } else {
        return null;
      }
      console.log('distFolder:', distFolder);
      const indexHtml = fs.existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
    
      // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
      server.engine('html', ngExpressEngine({
        bootstrap: AppServerModule,
      }));
    
      server.set('view engine', 'html');
      server.set('views', distFolder);
    
      // Example Express Rest API endpoints
      // server.get('/api/**', (req, res) => { });
      // Serve static files from /browser
      server.get('*.*', express.static(distFolder, {
        maxAge: '1y'
      }));
    
      // All regular routes use the Universal engine
      server.get('*', (req, res) => {
        res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
      });
    
      return server;
    }
    

    以防万一您想知道如何将web.config 文件复制到dist 文件夹的根目录,好吧,因为我正在使用 AppVeyor 进行 CI/CD,所以我已经修改了工件创建命令以包含 web.config (从 repo 源文件直接进入 .7z 文件)

    为什么不包括我的web.config

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <system.web>
        <httpRuntime enableVersionHeader="false" />
      </system.web>
      <system.webServer>
        <httpProtocol>
          <customHeaders>
            <add name="Strict-Transport-Security" value="max-age=31536000"/>
            <add name="X-Content-Type-Options" value="nosniff" />
            <add name="X-Frame-Options" value="DENY" />
            <add name="X-XSS-Protection" value="1; mode=block" />
            <remove name="X-Powered-By" />
          </customHeaders>
        </httpProtocol>
        <webSocket enabled="false" />
        <handlers>
          <!-- Indicates that the main.js file is a node.js site to be handled by the iisnode module -->
          <add name="iisnode" path="main.js" verb="*" modules="iisnode"/>
        </handlers>
        <rewrite>
          <rules>
            <rule name="HTTP to HTTPS redirect" stopProcessing="true">
              <match url="(.*)" />
              <conditions>
                <add input="{HTTPS}" pattern="off" ignoreCase="true" />
              </conditions>
              <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
            </rule>
            <!-- Do not interfere with requests for node-inspector debugging -->
            <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
              <match url="^main.js\/debug[\/]?" />
            </rule>
            <!-- All other URLs are mapped to the node.js site entry point -->
            <rule name="DynamicContent">
              <match url="^(?!.*login).*$"></match>
              <conditions>
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
              </conditions>
              <action type="Rewrite" url="main.js"/>
            </rule>
          </rules>
          <outboundRules>
            <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
              <match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" />
              <conditions>
                <add input="{HTTPS}" pattern="on" ignoreCase="true" />
              </conditions>
              <action type="Rewrite" value="max-age=31536000" />
            </rule>
          </outboundRules>
        </rewrite>
        <!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
        <security>
          <requestFiltering>
            <hiddenSegments>
              <remove segment="bin"/>
            </hiddenSegments>
          </requestFiltering>
        </security>
        <!-- Make sure error responses are left untouched -->
        <httpErrors existingResponse="PassThrough" />
    
        <!-- Restart the server if any of these files change -->
        <iisnode watchedFiles="web.config;*.js;browser/*.*" />
      </system.webServer>
    </configuration>
    

    我希望这可以在我的情况下帮助其他人,或者至少对辩论有用。没有人愿意在升级到版本 9 后尝试成功部署到 Azure 应用服务。请让我知道是否可以改进某些东西,也许是避免浏览器构建文件夹删除或其他什么的构建参数。干杯。

    【讨论】:

      【解决方案4】:

      经过 2 天的反复试验(Angular 8),以下流程对我有用

      • 假设你关注https://angular.io/guide/universal
        • 假设您将 src\tsconfig.server.json 更改为 --如果 tsconfig.server.json 已在 src 文件夹中生成,则使用此 注释

      {
        "extends": "./tsconfig.app.json",
        "compilerOptions": {
          "outDir": "../out-tsc/app-server",
          "module": "commonjs"
        },
        "files": [
          "src/main.server.ts" -- old
          "main.server.ts" -- use this
        ],
        "angularCompilerOptions": {
          "entryModule": "./app/app.server.module#AppServerModule"
        }
      }

      website_root:.
      │   server.js
      │   web.config
      │
      ├───dist
      │   └───browser
      │           3rdpartylicenses.txt
      │           favicon.ico
      │           index.html
      │           main-es2015.da6c4688eda738c0ae37.js
      │           main-es5.da6c4688eda738c0ae37.js
      │           polyfills-es2015.0ef207fb7b4761464817.js
      │           polyfills-es5.2b9ce34c123ac007a8ba.js
      │           runtime-es2015.e8a2810b3b08d6a1b6aa.js
      │           runtime-es5.e8a2810b3b08d6a1b6aa.js
      │           styles.09e2c710755c8867a460.css
      │
      └───server
              main.js

      部署到 Azure(灵感来自 Link's answer by **r3plica)**

      唯一的区别是额外的“复制文件”任务将服务器文件夹移动到根目录

      注意

      如果事情不起作用,请始终使用 node 指向 server.js 这个

      node <path to server.js>
      

      这会告诉你你犯错的最基本的事情

      【讨论】:

      • 您好,您是如何在构建期间或之后将文件 server.js 和 web.config 从项目根文件夹复制到 dist 根文件夹的?我也很想这样做,但我一直做不到。我已经尝试过 angular.json,但它不允许为服务器构建配置资产,在升级到 Angular 9 后也不鼓励使用 webpack,这就是我用来通过安装 copy-webpack-plugin 来复制文件的方法。有什么建议吗?
      • 我是在构建之后这样做的。使用 Azure 构建管道。如果您需要构建流程的 SS,我可以上传到某个地方
      • 哦,伙计,非常感谢,我们没有使用 Azure Build Pipes,我们使用 AppVeyor 进行 CI/CD,但整个周末我都在努力解决这个问题,最后我从中得到了一些东西,这是 Angula CLI 团队可以避免的黑客攻击。无论如何我都会发布我的“解决方案”。
      猜你喜欢
      • 2019-04-28
      • 1970-01-01
      • 2018-12-10
      • 1970-01-01
      • 2020-08-29
      • 1970-01-01
      • 2020-08-14
      • 2018-05-31
      • 1970-01-01
      相关资源
      最近更新 更多