如何在Azure应用服务(Web应用)中部署Angular Universal

问题描述 投票:0回答:1

我在没有服务器端渲染的情况下部署了 Angular 代码。已成功部署。 之后我将服务器端渲染集成到项目中。现在,当我尝试部署时,我显示“您无权查看此目录或页面。”

[您没有权限查看此目录或页面。]

我添加了 web.config 文件 Web.config

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <staticContent>
         <mimeMap fileExtension=".json" mimeType="application/json" />
         <remove fileExtension=".woff" />
         <mimeMap fileExtension=".woff" mimeType="application/font-woff" />
         <mimeMap fileExtension=".woff2" mimeType="font/woff2" />
      </staticContent>
        <rewrite>  
            <rules>  
                <rule name="Angular Routes" 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="/index.html" />  
                </rule>  
            </rules>  
        </rewrite>  
   </system.webServer>
</configuration>

在 server.ts 中,我使用 HOST=0.0.0.0 和 PORT=5000。其余部分默认为 Angular SSR 服务器.ts

import 'zone.js/node';

import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import AppServerModule from './src/main.server';

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/farmQ/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html'))
    ? join(distFolder, 'index.original.html')
    : join(distFolder, 'index.html');

  const commonEngine = new CommonEngine();

  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 Angular engine
  server.get('*', (req, res, next) => {
    const { protocol, originalUrl, baseUrl, headers } = req;

    commonEngine
      .render({
        bootstrap: AppServerModule,
        documentFilePath: indexHtml,
        url: `${protocol}://${headers.host}${originalUrl}`,
        publicPath: distFolder,
        providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
      })
      .then((html) => res.send(html))
      .catch((err) => next(err));
  });

  return server;
}

function run(): void {
  const port = process.env['SSR_PORT'] || 4000;
  //const PORT = process.env['PORT'] || 5000;
  const PORT = parseInt(process.env['PORT'] || '5000', 10);
  const HOST = '0.0.0.0';

  // Start up the Node server
  const server = app();
  // server.listen(port, () => {
  //   console.log(`Node Express server listening on http://localhost:${port}`);
  // });

  server.listen(PORT, HOST, () => {
    console.log(`Server listening on ${HOST}:${PORT}`);
  });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export default AppServerModule;

在我的package.json中添加ng后添加@angular/ssr "@angular/platform-server": "^17.3.2", “@角/ssr”:“^17.3.2”, "express": "^4.18.2", "@types/express": "^4.17.17", "@types/node": "^18.18.0", “浏览器同步”:“^3.0.0”,

package.json

{
  "name": "farmQ",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "npm run serve:ssr",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "serve:ssr": "node dist/farmQ/server/main.js --port=5000 --host=0.0.0.0",
    "build:ssr": "ng build && ng run farmQ:server",
    "build:dev:ssr": "ng build --configuration=dev && ng run farmQ:server:dev",
    "build:prod:ssr": "ng build --configuration=production && ng run farmQ:server:production",
    "build:qa:ssr": "ng build --configuration=qa && ng run farmQ:server:qa",
    "build:staging:ssr": "ng build --configuration=staging && ng run farmQ:server:staging",
    "prerender": "ng run farmQ:prerender"  
  },
  "private": true,
  "dependencies": {
    "@ag-grid-community/angular": "^31.0.0",
    "@angular/animations": "^17.3.2",
    "@angular/cdk": "^16.2.14",
    "@angular/common": "^17.3.2",
    "@angular/compiler": "^17.3.2",
    "@angular/core": "^17.3.2",
    "@angular/flex-layout": "^15.0.0-beta.42",
    "@angular/forms": "^17.3.2",
    "@angular/material": "^16.2.14",
    "@angular/platform-browser": "^17.3.2",
    "@angular/platform-browser-dynamic": "^17.3.2",
    "@angular/platform-server": "^17.3.2",
    "@angular/router": "^17.3.2",
    "@angular/ssr": "^17.3.2",
    "@ngx-translate/core": "^14.0.0",
    "@ngx-translate/http-loader": "^7.0.0",
    "ag-grid-angular": "^28.2.1",
    "ag-grid-community": "^28.2.1",
    "angularx-qrcode": "^17.0.0",
    "aws-sdk": "^2.1580.0",
    "bootstrap": "^5.3.3",
    "express": "^4.18.2",
    "font-awesome": "^4.7.0",
    "jquery": "^3.7.1",
    "lodash": "^4.17.21",
    "mock-browser": "^0.92.14",
    "moment": "^2.30.1",
    "ng-material-multilevel-menu": "^6.0.2",
    "ng-otp-input": "^1.9.3",
    "ngx-moment": "^6.0.2",
    "ngx-toastr": "^16.2.0",
    "primeflex": "^3.3.1",
    "primeicons": "^6.0.1",
    "primeng": "^17.12.0",
    "rxjs": "^7.4.0",
    "save": "^2.9.0",
    "sweetalert2": "^11.10.6",
    "tslib": "^2.3.0",
    "xlsx": "^0.18.5",
    "zone.js": "~0.14.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^17.3.2",
    "@angular/cli": "~17.3.2",
    "@angular/compiler-cli": "^17.3.2",
    "@types/express": "^4.17.17",
    "@types/jasmine": "~4.0.0",
    "@types/jquery": "^3.5.29",
    "@types/lodash": "^4.17.0",
    "@types/node": "^18.18.0",
    "@types/qrcode": "^1.5.5",
    "browser-sync": "^3.0.0",
    "jasmine-core": "~4.3.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.0.0",
    "typescript": "~5.4.3"
  }
}

我已经投入了很多时间,请为我提供一些解决方案。

谢谢你。

azure azure-web-app-service angular-universal
1个回答
0
投票

我使用 Angular Universal 创建了一个简单的 Angular 17 应用程序用于服务器端渲染,并已成功部署到 Azure 应用服务。

对于 Angular Universal,我运行了以下命令:

ng add @nguniversal/express-engine

下面是我的package.json和server.ts代码。

package.json:

{
  "name": "my-angular-app",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "serve:ssr:my-angular-app": "node dist/my-angular-app/server/server.mjs"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^17.3.0",
    "@angular/common": "^17.3.0",
    "@angular/compiler": "^17.3.0",
    "@angular/core": "^17.3.4",
    "@angular/forms": "^17.3.0",
    "@angular/platform-browser": "^17.3.0",
    "@angular/platform-browser-dynamic": "^17.3.0",
    "@angular/platform-server": "^17.3.4",
    "@angular/router": "^17.3.0",
    "@angular/ssr": "^17.3.4",
    "@nguniversal/express-engine": "^7.0.2",
    "express": "^4.18.2",
    "rxjs": "^7.8.1",
    "tslib": "^2.6.2",
    "zone.js": "^0.14.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^17.3.4",
    "@angular/cli": "^17.3.4",
    "@angular/compiler-cli": "^17.3.0",
    "@types/express": "^4.17.17",
    "@types/jasmine": "~5.1.0",
    "@types/node": "^18.18.0",
    "jasmine-core": "~5.1.0",
    "karma": "~6.4.0",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "typescript": "~5.4.2"
  }
}

服务器.ts

import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
import { fileURLToPath } from 'node:url';
import { dirname, join, resolve } from 'node:path';
import bootstrap from './src/main.server';
export function app(): express.Express {
  const server = express();
  const serverDistFolder = dirname(fileURLToPath(import.meta.url));
  const browserDistFolder = resolve(serverDistFolder, '../browser');
  const indexHtml = join(serverDistFolder, 'index.server.html');
  const commonEngine = new CommonEngine();
  server.set('view engine', 'html');
  server.set('views', browserDistFolder);
  server.get('*.*', express.static(browserDistFolder, {
    maxAge: '1y'
  }));
   server.get('*', (req, res, next) => {
    const { protocol, originalUrl, baseUrl, headers } = req;
    commonEngine
      .render({
        bootstrap,
        documentFilePath: indexHtml,
        url: `${protocol}://${headers.host}${originalUrl}`,
        publicPath: browserDistFolder,
        providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
      })
      .then((html) => res.send(html))
      .catch((err) => next(err));
  });
  return server;
}
function run(): void {
  const port = process.env['PORT'] || 5000;
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}
run();

如果要添加端口,可以将其添加到server.ts文件中。

我使用VS Code将Angular App部署到Azure,成功了,如下图。

enter image description here

如果要部署到 Azure Linux Web,请添加以下启动命令:

pm2 serve /home/site/wwwroot/dist/<WebAppName>/browser --no-daemon --spa

如下图。

enter image description here

如果要将其部署到 Azure Windows 应用程序,请在“配置”->“路径映射”->“虚拟路径”中添加路径

site\wwwroot\dist\<WebAppName>\browser

如下图。

enter image description here

输出

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.