139 lines
3.5 KiB
TypeScript
139 lines
3.5 KiB
TypeScript
import createMiddleware from "next-intl/middleware"
|
|
import { NextRequest, NextResponse } from "next/server"
|
|
|
|
import { getClientIp } from "@supercharge/request-ip"
|
|
|
|
import { IS_PROD } from "~/lib/constants"
|
|
|
|
import { defaultLocale, locales } from "./i18n"
|
|
|
|
// HTTPWhiteListPaths: White list of path for plain http request, no HTTPS redirect
|
|
const HTTPWhitelistPaths = ["/api/healthcheck"]
|
|
|
|
export const config = {
|
|
// Skip all paths that should not be internationalized. This example skips the
|
|
// folders "api", "_next" and all files with an extension (e.g. favicon.ico)
|
|
matcher: ["/((?!api|_next|_vercel|.*\\..*).*)"],
|
|
}
|
|
|
|
export async function middleware(req: NextRequest) {
|
|
const handleI18nRouting = createMiddleware({
|
|
locales,
|
|
defaultLocale,
|
|
localePrefix: "never",
|
|
})
|
|
|
|
const { pathname } = req.nextUrl
|
|
|
|
if (
|
|
IS_PROD &&
|
|
req.headers.get("x-forwarded-proto") !== "https" &&
|
|
!HTTPWhitelistPaths.includes(pathname)
|
|
) {
|
|
let cfHttps = false
|
|
try {
|
|
if (
|
|
JSON.parse(req.headers.get("cf-visitor") || "{}").scheme === "https"
|
|
) {
|
|
cfHttps = true
|
|
}
|
|
} catch (error) {
|
|
console.error(error)
|
|
}
|
|
if (!cfHttps) {
|
|
// return NextResponse.redirect(
|
|
// `https://${req.headers.get("host")}${req.nextUrl.pathname}${
|
|
// req.nextUrl.search
|
|
// }`,
|
|
// 301,
|
|
// )
|
|
}
|
|
}
|
|
|
|
if (
|
|
pathname === "/feed.xml" ||
|
|
pathname === "/atom.xml" ||
|
|
pathname === "/feed/xml"
|
|
) {
|
|
return NextResponse.redirect(
|
|
`https://${
|
|
req.headers.get("x-forwarded-host") || req.headers.get("host")
|
|
}/feed`,
|
|
301,
|
|
)
|
|
}
|
|
|
|
console.debug(`${req.method} ${req.nextUrl}`)
|
|
|
|
const response = handleI18nRouting(req)
|
|
|
|
// https://github.com/vercel/next.js/issues/46618#issuecomment-1450416633
|
|
response.headers.set("x-xlog-pathname", pathname)
|
|
response.headers.set("x-xlog-search", req.nextUrl.search)
|
|
response.headers.set("x-xlog-ip", getClientIp(req) || "")
|
|
|
|
if (
|
|
pathname.startsWith("/api/") ||
|
|
pathname.startsWith("/dashboard") ||
|
|
pathname.startsWith("/_next/") ||
|
|
pathname.startsWith("/assets/") ||
|
|
pathname.startsWith("/locales/") ||
|
|
pathname.startsWith("/site/") ||
|
|
pathname.match(/^\/(workbox|worker|fallback)-\w+\.js(\.map)?$/) ||
|
|
pathname === "/sw.js" ||
|
|
pathname === "/sw.js.map" ||
|
|
pathname === "/monitoring" ||
|
|
pathname === "favicon.ico"
|
|
) {
|
|
return response
|
|
}
|
|
|
|
let tenant: {
|
|
subdomain?: string
|
|
redirect?: string
|
|
} = {}
|
|
try {
|
|
tenant = await (
|
|
await fetch(
|
|
new URL(
|
|
`/api/host2handle?host=${
|
|
req.headers.get("x-forwarded-host") || req.headers.get("host")
|
|
}`,
|
|
req.url,
|
|
),
|
|
)
|
|
).json()
|
|
} catch (error) {
|
|
console.error(error)
|
|
}
|
|
|
|
if (tenant?.redirect && IS_PROD && !pathname.startsWith("/feed")) {
|
|
return NextResponse.redirect(
|
|
`${tenant.redirect}${req.nextUrl.pathname}${req.nextUrl.search}`,
|
|
)
|
|
}
|
|
|
|
response.headers.set("x-xlog-handle", tenant.subdomain || "")
|
|
|
|
if (tenant?.subdomain) {
|
|
const newResponse = NextResponse.rewrite(
|
|
new URL(
|
|
`/${response.headers.get(
|
|
"x-middleware-request-x-next-intl-locale",
|
|
)}/site/${tenant?.subdomain}${pathname === "/" ? "" : pathname}${
|
|
req.nextUrl.search
|
|
}`,
|
|
req.url,
|
|
),
|
|
)
|
|
response.headers.forEach((value, key) => {
|
|
if (key !== "x-middleware-rewrite") {
|
|
newResponse.headers.set(key, value)
|
|
}
|
|
})
|
|
return newResponse
|
|
}
|
|
|
|
return response
|
|
}
|