2

使用 Vite 的开发服务器,如果我尝试访问一个不存在的 URL(例如localhost:3000/nonexistent/index.html),我会收到一个404错误。相反,我会收到一个200状态码以及localhost:3000/index.html.

如何配置 Vite 以便404在这种情况下返回 a ?

(这个问题:Serve a 404 page with app created with Vue-CLI非常相似,但与基于 Webpack 的 Vue-CLI 而不是 Vite 相关。)

4

3 回答 3

1

Vite 2.6.11 不支持禁用历史 API 回退,尽管有一个开放的拉取请求引入了一个可用于禁用历史回退中间件( vitejs/vite#4640)的配置。

作为一种解决方法,您可以添加一个自定义插件来有效地禁用历史 API 回退。Vite 的插件 API 包含允许将自定义中间件添加到底层连接实例的configureServer()钩子。您可以添加一个中间件,为未找到的 URL 请求发送 404 状态代码。

这是编写该插件的一种方法:

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

function disableHistoryFallback() {
  const path = require('path')
  const fs = require('fs')

  const ALLOWLIST = [
    // internal requests
    /^\/__vite_ping/,
    /^\/@vite\/client/,
    /^\/@id/,
    /^\/__open-in-editor/,

    // no check needed
    /^\/$/,
    /^\/index.html/,
  ]
  return {
    name: 'disable-history-fallback',
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        // remove query params from url (e.g., cache busts)
        const url = req.url.split('?')[0]

        if (ALLOWLIST.some(pattern => pattern.test(url))) {
          return next()
        }

        if (!fs.existsSync(path.join(__dirname, url))) {
          console.warn('URL not found:', url)
          res.statusCode = 404
          res.end()
        } else {
          next()
        }
      })
    }
  }
}

export default defineConfig({
  plugins: [vue(), disableHistoryFallback()],
})
于 2021-10-25T16:56:41.407 回答
0

这是一种不尝试检查磁盘上的内容的方法(这对我来说产生了不正确的行为)。

相反,这种方法:

  1. 移除 Vite 的 SPA 后备中间件
  2. 它使用 Vite 的内置 HTML 转换并返回/dir/index.html(如果存在)/dir/dir/请求
  3. 404 其他一切
// express not necessary, but its API does simplify things
const express = require("express");
const { join } = require("path");
const { readFile } = require("fs/promises");

// ADJUST THIS FOR YOUR PROJECT
const PROJECT_ROOT = join(__dirname, "..");

function removeHistoryFallback() {
  return {
    name: "remove-history-fallback",
    configureServer(server) {
      // returned function runs AFTER Vite's middleware is built
      return function () {
        removeViteSpaFallbackMiddleware(server.middlewares);
        server.middlewares.use(transformHtmlMiddleware(server));
        server.middlewares.use(notFoundMiddleware());
      };
    },
  };
}

function removeViteSpaFallbackMiddleware(middlewares) {
  const { stack } = middlewares;
  const index = stack.findIndex(function (layer) {
    const { handle: fn } = layer;
    return fn.name === "viteSpaFallbackMiddleware";
  });
  if (index > -1) {
    stack.splice(index, 1);
  } else {
    throw Error("viteSpaFallbackMiddleware() not found in server middleware");
  }
}

function transformHtmlMiddleware(server) {
  const middleware = express();
  middleware.use(async (req, res, next) => {
    try {
      const rawHtml = await getIndexHtml(req.path);
      const transformedHtml = await server.transformIndexHtml(
        req.url, rawHtml, req.originalUrl
      );
      
      res.set(server.config.server.headers);
      res.send(transformedHtml);
    } catch (error) {
      return next(error);
    }
  });
  
  // named function for easier debugging
  return function customViteHtmlTransformMiddleware(req, res, next) {
    middleware(req, res, next);
  };
}

async function getIndexHtml(path) {
  const indexPath = join(PROJECT_ROOT, path, "index.html");
  return readFile(indexPath, "utf-8");
}

function notFoundMiddleware() {
  const middleware = express();
  middleware.use((req, res) => {
    const { method, path } = req;
    res.status(404);
    res.type("html");
    res.send(`<pre>Cannot ${method} ${path}</pre>`);
  });
  return function customNotFoundMiddleware(req, res, next) {
    middleware(req, res, next);
  };
}

module.exports = {
  removeHistoryFallback,
};

有趣的是,Vite 似乎采取的立场是:

  • 它只是一个开发和构建工具,不能用于生产
  • 构建的文件是静态服务的,因此,它不附带生产服务器

但是,对于静态文件服务器:

  • 当请求目录时,静态文件服务器的某些配置将返回索引文件
  • 当找不到文件时,它们通常不会回退到服务index.html,而是在这些情况下返回 404

因此,当 Vite 的开发服务器针对没有它的生产环境时,它具有这种回退行为并没有多大意义。如果有一种“正确”的方式来关闭历史回退,同时保持其余的服务行为(HTML 转换等),那就太好了。

于 2022-02-27T06:45:02.103 回答
0

您可以修改后备中间件以更改默认行为或您想要的任何其他内容。这是一个例子。https://github.com/legend-chen/vite-404-redirect-plugin

于 2022-02-26T07:40:13.413 回答