From d651ac7c60e9d0d78b38dc254762f5646e99acbc Mon Sep 17 00:00:00 2001 From: xieyimian Date: Tue, 19 Mar 2024 21:57:02 +0800 Subject: [PATCH] refactor(middleware): oops page for php bots (#218) * refactor(middleware): oops page for php bots * refactor(middleware): wip * refactor(middleware): simple ops page * chore: fix skip logic * chore: rename * chore: rename --- next.config.js | 9 +++++ src/app/404.tsx | 7 ++++ src/app/[community]/error.tsx | 3 -- src/app/oops/page.tsx | 35 +++++++++++++++++++ src/app/oops/styles/index.ts | 18 ++++++++++ src/app/providers/RootStoreProvider.tsx | 21 ++++++++--- src/app/queries/helper.ts | 18 +++++----- src/app/queries/index.ts | 24 ++++++------- .../ThreadSidebar/CommunityBrief.tsx | 2 +- src/hooks/useMetric.ts | 4 +-- src/middleware.ts | 21 +++++------ src/middlewares/avoid-scan.ts | 17 +++++++++ src/middlewares/helper.ts | 20 +++++++++++ src/middlewares/oops.ts | 17 +++++++++ src/widgets/Footer/DesktopView/index.tsx | 4 +++ src/widgets/GlobalLayout/index.tsx | 1 + utils/constant/route.ts | 4 ++- 17 files changed, 182 insertions(+), 43 deletions(-) create mode 100644 src/app/404.tsx create mode 100644 src/app/oops/page.tsx create mode 100644 src/app/oops/styles/index.ts create mode 100644 src/middlewares/avoid-scan.ts create mode 100644 src/middlewares/helper.ts create mode 100644 src/middlewares/oops.ts diff --git a/next.config.js b/next.config.js index 5965ce0b9..f103fc892 100755 --- a/next.config.js +++ b/next.config.js @@ -64,6 +64,15 @@ const nextConfig = { }, ], }, + { + source: '/oops', + headers: [ + { + key: 'cache-control', + value: 's-maxage=6000, stale-while-revalidate=30', + }, + ], + }, ] }, } diff --git a/src/app/404.tsx b/src/app/404.tsx new file mode 100644 index 000000000..8603caf6e --- /dev/null +++ b/src/app/404.tsx @@ -0,0 +1,7 @@ +import ErrorPage from 'next/error' + +const NotFound = () => { + return +} + +export default NotFound diff --git a/src/app/[community]/error.tsx b/src/app/[community]/error.tsx index 6ba90a380..3febee238 100644 --- a/src/app/[community]/error.tsx +++ b/src/app/[community]/error.tsx @@ -1,12 +1,9 @@ 'use client' -import ErrorPage from '@/widgets/ErrorPage' - const ErrorCommunity = () => { return (

Community Page Error

-
) } diff --git a/src/app/oops/page.tsx b/src/app/oops/page.tsx new file mode 100644 index 000000000..a36973b38 --- /dev/null +++ b/src/app/oops/page.tsx @@ -0,0 +1,35 @@ +'use client' + +import { useRouter } from 'next/navigation' + +import { ROUTE } from '@/constant/route' + +import Button from '@/widgets/Buttons/Button' +import { LinkAble } from '@/widgets/Common' + +import { Wrapper, InnerWrapper, Footer } from './styles' +// import ErrorPage from 'next/error' + +const OopsPage = () => { + const router = useRouter() + + return ( + + +

Oops

+

the content you looking for is not exist

+
+ + + + + +
+
+
+ ) +} + +export default OopsPage diff --git a/src/app/oops/styles/index.ts b/src/app/oops/styles/index.ts new file mode 100644 index 000000000..23181ae62 --- /dev/null +++ b/src/app/oops/styles/index.ts @@ -0,0 +1,18 @@ +import Link from 'next/link' + +import styled, { css, theme } from '@/css' + +export const Wrapper = styled.div` + ${css.column('align-both')}; + width: 100%; + height: 68vh; + position: relative; +` +export const InnerWrapper = styled.div` + ${css.column('align-start')}; + position: relative; +` +export const Footer = styled.div` + ${css.row()}; + margin-top: 20px; +` diff --git a/src/app/providers/RootStoreProvider.tsx b/src/app/providers/RootStoreProvider.tsx index 77ea8c97c..e6e7f871b 100644 --- a/src/app/providers/RootStoreProvider.tsx +++ b/src/app/providers/RootStoreProvider.tsx @@ -1,9 +1,11 @@ 'use client' -import { FC, ReactNode, memo } from 'react' +import { FC, ReactNode, memo, useEffect } from 'react' import { Provider } from 'mobx-react' import { enableStaticRendering } from 'mobx-react-lite' +import { useRouter } from 'next/navigation' + import { useStore } from '@/stores/init' import { @@ -31,6 +33,19 @@ type TProps = { const RootStoreWrapper: FC = ({ children }) => { const userHasLogin = false + // const router = useRouter() + + // useEffect(() => { + // const handleRedirect = async () => { + // if (!community) { + // await router.push('/oops') + // } + // } + + // handleRedirect() + // }, []) + + const theme = useThemeFromURL() const metric = useMetric() const activeThread = useThreadParam() @@ -47,10 +62,6 @@ const RootStoreWrapper: FC = ({ children }) => { const wallpaper = useWallpaper(community) const filterSearchParams = useFilterSearchParams() - // NOTE: 目前在没有启动后端的情况下,如果这行代码出现在 useCommunity 之前,会导致 build 后的代码疯狂 - // post 到 /GraphiQL, 奇怪的行为。。,很怀疑是 URQL 客户端的 Bug .. - const theme = useThemeFromURL() - const store = useStore({ metric, articles: { diff --git a/src/app/queries/helper.ts b/src/app/queries/helper.ts index bd6dbd8fb..1a1c40d06 100644 --- a/src/app/queries/helper.ts +++ b/src/app/queries/helper.ts @@ -22,7 +22,7 @@ import { THREAD } from '@/constant/thread' import URL_PARAM from '@/constant/url_param' import { nilOrEmpty } from '@/validator' import { - LANDIN_ROUTES, + STATIC_ROUTES, DASHBOARD_ROUTE, DASHBOARD_BASEINFO_ROUTE, DASHBOARD_SEO_ROUTE, @@ -44,23 +44,23 @@ export const commonRes = (result): TGQSSRResult => { } } -export const useIsStaticQuery = (): boolean => { +export const useIsFrameworkQuery = (): boolean => { const pathname = usePathname() return startsWith('/_next', pathname) || startsWith('/_vercel', pathname) } -export const useLandingPages = (): boolean => { +export const useIsStaticPages = (): boolean => { const pathname = usePathname() - return includes(pathname, LANDIN_ROUTES) + return includes(pathname, STATIC_ROUTES) } -export const useSkipLandingQuery = (): boolean => { - const isStaticQuery = useIsStaticQuery() - const isLandingPages = useLandingPages() +export const useSkipStaticQuery = (): boolean => { + const isFrameworkQuery = useIsFrameworkQuery() + const isStaticPages = useIsStaticPages() - return isStaticQuery || isLandingPages + return isFrameworkQuery || isStaticPages } export const useCommunityParam = (): string => { @@ -114,7 +114,7 @@ export const useArticleParams = (): TArticleParams => { } export const parseCommunity = (communityPath: string): string => { - if (!communityPath) return HCN + if (!communityPath) return null // HCN if (communityPath === '_next') return null return communityPath diff --git a/src/app/queries/index.ts b/src/app/queries/index.ts index de513e83f..8f0c66b5e 100644 --- a/src/app/queries/index.ts +++ b/src/app/queries/index.ts @@ -34,8 +34,8 @@ import { useArticleParams, useCommunityParam, useThreadParam, - useIsStaticQuery, - useSkipLandingQuery, + useIsFrameworkQuery, + useSkipStaticQuery, useIdParam, // parseWallpaper, @@ -71,7 +71,7 @@ export const useMetric = (): TMetric => { } // export const useSession = (): TSessionRes => { -// const isStaticQuery = useIsStaticQuery() +// const isStaticQuery = useIsFrameworkQuery() // const [result] = useQuery({ // query: P.sessionState, @@ -99,7 +99,7 @@ export const useMetric = (): TMetric => { export const useCommunity = (userHasLogin: boolean): TCommunityRes => { const slug = useCommunityParam() - const skipLandingQuery = useSkipLandingQuery() + const skipLandingQuery = useSkipStaticQuery() const [result] = useQuery({ query: P.community, @@ -118,7 +118,7 @@ export const useCommunity = (userHasLogin: boolean): TCommunityRes => { export const useTags = (): TTagsRes => { const community = useCommunityParam() - const skipLandingQuery = useSkipLandingQuery() + const skipLandingQuery = useSkipStaticQuery() const thread = useThreadParam() const [result] = useQuery({ @@ -138,7 +138,7 @@ export const useTags = (): TTagsRes => { export const usePagedPosts = (userHasLogin: boolean): TPagedPostsRes => { const filter = usePagedArticlesParams() const thread = useThreadParam() - const skipLandingQuery = useSkipLandingQuery() + const skipLandingQuery = useSkipStaticQuery() const id = useIdParam() const [result] = useQuery({ @@ -155,7 +155,7 @@ export const usePagedPosts = (userHasLogin: boolean): TPagedPostsRes => { export const usePagedChangelogs = (userHasLogin: boolean): TPagedChangelogsRes => { const filter = usePagedArticlesParams() - const skipLandingQuery = useSkipLandingQuery() + const skipLandingQuery = useSkipStaticQuery() const thread = useThreadParam() const [result] = useQuery({ @@ -172,7 +172,7 @@ export const usePagedChangelogs = (userHasLogin: boolean): TPagedChangelogsRes = export const usePost = (userHasLogin: boolean): TPostRes => { const { community, id } = useArticleParams() - const skipLandingQuery = useSkipLandingQuery() + const skipLandingQuery = useSkipStaticQuery() const thread = useThreadParam() const [result] = useQuery({ @@ -189,7 +189,7 @@ export const usePost = (userHasLogin: boolean): TPostRes => { export const useChangelog = (userHasLogin: boolean): TChangelogRes => { const { community, id } = useArticleParams() - const skipLandingQuery = useSkipLandingQuery() + const skipLandingQuery = useSkipStaticQuery() const thread = useThreadParam() const [result] = useQuery({ @@ -206,7 +206,7 @@ export const useChangelog = (userHasLogin: boolean): TChangelogRes => { export const useGroupedKanbanPosts = (userHasLogin: boolean): TGroupedKanbanPostsRes => { const community = useCommunityParam() - const skipLandingQuery = useSkipLandingQuery() + const skipLandingQuery = useSkipStaticQuery() const thread = useThreadParam() const [result] = useQuery({ @@ -225,7 +225,7 @@ export const useGroupedKanbanPosts = (userHasLogin: boolean): TGroupedKanbanPost * wallpaper related settings for all page */ export const useWallpaper = (community: TCommunity): TParsedWallpaper => { - const isStaticQuery = useIsStaticQuery() + const isStaticQuery = useIsFrameworkQuery() // @ts-ignore return !isStaticQuery ? parseWallpaper(community) : {} @@ -235,7 +235,7 @@ export const useWallpaper = (community: TCommunity): TParsedWallpaper => { * general dashboard settings for all page */ export const useDashboard = (community: TCommunity): TParseDashboard => { - const isStaticQuery = useIsStaticQuery() + const isStaticQuery = useIsFrameworkQuery() const pathname = usePathname() // @ts-ignore diff --git a/src/containers/thread/PostThread/ThreadSidebar/CommunityBrief.tsx b/src/containers/thread/PostThread/ThreadSidebar/CommunityBrief.tsx index 83fbce3d7..3619e36fc 100644 --- a/src/containers/thread/PostThread/ThreadSidebar/CommunityBrief.tsx +++ b/src/containers/thread/PostThread/ThreadSidebar/CommunityBrief.tsx @@ -44,7 +44,7 @@ const CommunityBrief: FC = ({ show }) => { - {meta.postsCount} + {meta?.postsCount} diff --git a/src/hooks/useMetric.ts b/src/hooks/useMetric.ts index 6c5b507ee..186728155 100644 --- a/src/hooks/useMetric.ts +++ b/src/hooks/useMetric.ts @@ -7,7 +7,7 @@ import { includes } from 'ramda' import type { TMetric } from '@/spec' import METRIC from '@/constant/metric' import { BANNER_LAYOUT } from '@/constant/layout' -import { LANDIN_ROUTES } from '@/constant/route' +import { STATIC_ROUTES } from '@/constant/route' /** * NOTE: should use observer to wrap the component who use this hook @@ -21,7 +21,7 @@ const useMetric = (): TMetric => { const pathname = usePathname() - if (includes(pathname, LANDIN_ROUTES)) { + if (includes(pathname, STATIC_ROUTES)) { return METRIC.HOME } diff --git a/src/middleware.ts b/src/middleware.ts index c008810c5..132072b22 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,18 +1,19 @@ -import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' +import { applyMiddleware } from './middlewares/helper' // import { themeMiddleware } from './middlewares/theme' import { queryWhitelistMiddleware } from './middlewares/query-whitelist' +import { oopsMiddleware } from './middlewares/oops' +import { avoidScanMiddleware } from './middlewares/avoid-scan' export function middleware(request: NextRequest) { - // const response = themeMiddleware(request) - // if (response instanceof NextResponse) return response + // middleware in this array will be applied in order + const middlewareFunctions = [ + avoidScanMiddleware, + oopsMiddleware, + queryWhitelistMiddleware, + // ... more middlewares + ] - // whitelist the query parameters to improve CDN caching - const response = queryWhitelistMiddleware(request) - if (response instanceof NextResponse) return response - - // return response instanceof NextResponse ? response : NextResponse.next() - - return NextResponse.next() + return applyMiddleware(middlewareFunctions, request) } diff --git a/src/middlewares/avoid-scan.ts b/src/middlewares/avoid-scan.ts new file mode 100644 index 000000000..f4edf0e56 --- /dev/null +++ b/src/middlewares/avoid-scan.ts @@ -0,0 +1,17 @@ +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +import { ROUTE } from '@/constant/route' + +export function avoidScanMiddleware(req: NextRequest) { + const { pathname } = req.nextUrl + + // 检查pathname是否以.php或.php7结束 + if (pathname.endsWith('.php') || pathname.endsWith('.php7')) { + // 重定向到/oops页面 + return NextResponse.redirect(new URL(ROUTE.OOPS, req.url)) + } + + // 如果路径不以.php或.php7结束,则继续处理后续中间件 + return NextResponse.next() +} diff --git a/src/middlewares/helper.ts b/src/middlewares/helper.ts new file mode 100644 index 000000000..c4f6facde --- /dev/null +++ b/src/middlewares/helper.ts @@ -0,0 +1,20 @@ +import { NextResponse } from 'next/server' + +/** + * chain the middlewares and apply them to the request + */ +export function applyMiddleware(middlewareFns, req) { + for (const middlewareFn of middlewareFns) { + const response = middlewareFn(req) + // 如果中间件执行结果是重定向或重写,那么就返回该响应并且不再执行后续中间件 + + if (response instanceof NextResponse) { + // 检查状态码是否代表重定向 + if (response.status >= 300 && response.status < 400) { + return response + } + } + } + + return NextResponse.next() +} diff --git a/src/middlewares/oops.ts b/src/middlewares/oops.ts new file mode 100644 index 000000000..7ef7e7ea1 --- /dev/null +++ b/src/middlewares/oops.ts @@ -0,0 +1,17 @@ +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +import { ROUTE } from '@/constant/route' + +export function oopsMiddleware(req: NextRequest) { + const { pathname } = req.nextUrl + + // 若路径为 /404,则重定向到自定义404页面 + // just demo + if (pathname === '/404') { + // return NextResponse.rewrite(new URL(ROUTE.OOPS, req.url)) + return NextResponse.redirect(new URL(ROUTE.OOPS, req.url)) + } + + return NextResponse.next() +} diff --git a/src/widgets/Footer/DesktopView/index.tsx b/src/widgets/Footer/DesktopView/index.tsx index c9b45228d..827b8bd1d 100644 --- a/src/widgets/Footer/DesktopView/index.tsx +++ b/src/widgets/Footer/DesktopView/index.tsx @@ -10,6 +10,7 @@ import { observer } from 'mobx-react-lite' import { FOOTER_LAYOUT } from '@/constant/layout' import useFooterLinks from '@/hooks/useFooterLinks' import useMetric from '@/hooks/useMetric' +import useViewingCommunity from '@/hooks/useViewingCommunity' import { buildLog } from '@/logger' @@ -22,9 +23,12 @@ import { Wrapper, InnerWrapper } from '../styles' const _log = buildLog('C:Footer') const Footer: FC = () => { + const { slug } = useViewingCommunity() const { layout } = useFooterLinks() const metric = useMetric() + if (!slug) return null // TODO: link to groupher home + return ( diff --git a/src/widgets/GlobalLayout/index.tsx b/src/widgets/GlobalLayout/index.tsx index 9698594e0..a3b9a9b03 100644 --- a/src/widgets/GlobalLayout/index.tsx +++ b/src/widgets/GlobalLayout/index.tsx @@ -60,6 +60,7 @@ const GlobalLayout: FC = ({ children }) => { const bgColor = `${blurRGB(themeData.htmlBg, gossBlur)}` + console.log('## globalLayout rendering ') // const isMobile = false // useEffect(() => { diff --git a/utils/constant/route.ts b/utils/constant/route.ts index 48e722f88..2a5f0808d 100755 --- a/utils/constant/route.ts +++ b/utils/constant/route.ts @@ -102,6 +102,8 @@ export const ROUTE = { USER: 'user', PRICE: 'pricing', + OOPS: 'oops', + ...NON_COMMUNITY_ROUTE, DASHBOARD: { @@ -109,4 +111,4 @@ export const ROUTE = { }, } -export const LANDIN_ROUTES = ['/', '/pricing', '/book-demo'] +export const STATIC_ROUTES = ['/', '/pricing', '/book-demo', '/oops']