【问题标题】:Angular 6 SSR : a true 404 / not found page with an 404 HTTP status codeAngular 6 SSR:具有 404 HTTP 状态代码的真正 404 / 未找到页面
【发布时间】:2019-03-10 20:24:57
【问题描述】:

我很难解决一个 404 页面,该页面返回给导航器/爬虫一个特定的 HTTP 状态代码:404。 遵循https://angular.io/guide/universal 中的 SSR 指南,我的应用程序可以正确使用 SSR。

我在 app-routing.module.ts 中设置了一个“PageNotfound”路由:

{path: '*', component: NotFoundComponent}

但显然它仍然返回 200 作为 http 返回状态。 如何更改此特定路线的 http 返回码?

【问题讨论】:

    标签: angular server-side-rendering


    【解决方案1】:

    将此添加到组件NotFoundComponent

    import {Component, Inject, OnInit, Optional, PLATFORM_ID} from '@angular/core';
    import {isPlatformBrowser} from '@angular/common';
    import {RESPONSE} from '@nguniversal/express-engine/tokens';
    import {Response} from 'express';
    
    @Component({
      selector: 'app-not-found',
      templateUrl: './not-found.component.html',
      styleUrls: ['./not-found.component.scss']
    })
    export class NotFoundComponent implements OnInit {
    
      constructor(@Inject(PLATFORM_ID) private platformId: Object,
                  @Optional() @Inject(RESPONSE) private response: Response) {
      }
    
    
      ngOnInit() {
        if (!isPlatformBrowser(this.platformId)) {
          this.response.status(404);
        }
      }
    }
    

    将 server.js 文件修改为此

    import {REQUEST, RESPONSE} from '@nguniversal/express-engine/tokens';
    import {ValueProvider} from '@angular/core';
    
    
    app.engine('html', (_, options, callback) => {
      renderModuleFactory(AppServerModuleNgFactory, {
        // Our index.html
        document: template,
        url: options.req.url,
        extraProviders: [
          // make req and response accessible when angular app runs on server
          <ValueProvider>{
            provide: REQUEST,
            useValue: options.req
          },
          <ValueProvider>{
            provide: RESPONSE,
            useValue: options.req.res,
          },
        ]
      }).then(html => {
        callback(null, html);
      });
    });
    

    【讨论】:

    • 您好,灭虫者,非常感谢您的回复。不幸的是,当我在构造函数中设置注入“响应”字段时,编译失败:ERROR in ./node_modules/cookie-signature/index.js Module not found: Error: Can't resolve 'crypto' in '/home/germain.sigety/workspace-typescript/ng-pas/node_modules/cookie-signature' ERROR in ./node_modules/etag/index.js Module not found: Error: Can't resolve 'crypto' in '/home/germain.sigety/workspace-typescript/ng-pas/node_modules/etag' ERROR in ./node_modules/destroy/index.js...你有什么想法吗?
    • 再次感谢您的宝贵时间 不幸的是,我没有 server.js,只有 server.ts(打字稿)。我的 app.engine 函数调用非常不同:app.engine('html', ngExpressEngine({ bootstrap: AppServerModuleNgFactory, providers: [ provideModuleMap(LAZY_MODULE_MAP) ] })); 您的解决方案是否适用于 Angular 6?如果我用你的方法替换我的方法,它不会编译。
    • 这个问题有什么进展吗?
    • @dcballs 我找到的唯一方法是stackoverflow.com/a/57677168/1990451 ...
    • 请帮助我获取 Angular 9 404 状态码 - stackoverflow.com/questions/70926063/…
    【解决方案2】:

    过时了。自 Angular 9 以来,问题已解决。仅用于

    虽然https://github.com/angular/universal/tree/master/modules/express-engine 此处有很好的记录,但建议的令牌不起作用。

    它在 SSR 中只是未定义(在客户端很容易模拟它)。

    但是有一个(非常)肮脏的解决方案。

    只需在您的 404 页面上添加一些标记(将 whatevervaluehere 更改为独特且无意义的内容):

    <!-- indicator for SSR to return 404 status code -->
    <!-- MUST BE LEFT HERE -->
    <input type="hidden" value="whatevervaluehere">
    

    在 server.ts 中

    app.get('*', (req, res) => {
      res.render('index', {
        req,
        res,
      }, (err: Error, html: string) => {
        res.status(html && html.includes('whatevervaluehere') ? 404 : html ? 200 : 500).send(html || err.message);
      });
    });
    

    再次,非常非常脏。但是,有效。

    【讨论】:

    【解决方案3】:

    对我来说,以下 sn-p 有效(Angular 8.2.11)。无需更改默认的 server.ts 文件。

    import { Component, OnInit, Inject, PLATFORM_ID, Optional } from '@angular/core';
    import { REQUEST } from '@nguniversal/express-engine/tokens';
    import { isPlatformServer } from '@angular/common';
    import { Request } from 'express';
    
    @Component({
      selector: 'app-error-not-found',
      templateUrl: './error-not-found.component.html',
      styleUrls: ['./error-not-found.component.scss']
    })
    export class ErrorNotFoundComponent implements OnInit {
    
      constructor(
        @Inject(PLATFORM_ID) private platformId: any,
        @Optional() @Inject(REQUEST) private request: Request
      ) { }
    
      ngOnInit() {
        if (isPlatformServer(this.platformId)) {
          if (this.request.res) {
            this.request.res.status(404);
          }
        }
      }
    
    }
    

    当然,我们需要我们的路线是这样的:

    export const routes: Routes = [
      ...
      { path: '404', component: ErrorNotFoundComponent },
      { path: '**', redirectTo: '/404' }
    ];
    

    【讨论】:

    • 这会将 express 导入前端构建。
    • 它只是从 Express 中导入输入 Request,而不是库本身。它不会包含在构建中。
    • 在 Angular 9 中工作,谢谢。在之前的版本中无法使用...
    猜你喜欢
    • 2022-08-10
    • 2018-11-28
    • 2011-11-21
    • 2019-03-15
    • 2019-07-30
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    • 2021-08-29
    相关资源
    最近更新 更多