Saber2pr's Blog

token转发

在 login 后把 token 存到 cookie,浏览器每次访问时 nextjs 从 req.headers.cookie 中解析出 token,然后通过 Authorization:Bearer 发给 java 后端。

import axios, { AxiosError } from 'axios'
import { ParsedUrlQuery } from 'querystring'

import Cookies from 'universal-cookie'

import { getToken } from './getToken'
import { printReqUrl, resolveResponse } from './interceptors'

import type { AxiosInstance } from 'axios'
import type { GetServerSideProps, GetServerSidePropsContext } from 'next'
type Props = { [key: string]: any }

type AxiosHandler<P extends Props = Props> = (
  request: AxiosInstance,
  ctx: GetServerSidePropsContext<ParsedUrlQuery>
) => P | Promise<P>

export const ApiConfig = {
  log: true,
  target: 'xxx',
}

export const getToken = (cookie: string) => {
  const cookies = new Cookies(cookie)
  return cookies.get('token')
}

/**
 * 注入Axios实例
 * 1. 服务端渲染时转发token
 * 2. HTTP异常处理
 */
export const withAxios = <P>(
  handler: AxiosHandler<P>
): GetServerSideProps => async (ctx) => {
  const cookie = ctx?.req?.headers?.cookie
  const token = getToken(cookie)

  const request = axios.create({
    baseURL: ApiConfig.target,
    headers: {
      Authorization: `Bearer ${token}`,
    },
  })

  request.interceptors.request.use(printReqUrl)
  request.interceptors.response.use(resolveResponse)

  let props = {}
  try {
    // 服务端HTTP Exception统一捕获
    props = await handler(request, ctx)
  } catch (error) {
    const axiosError: AxiosError = error
    const code = axiosError?.response?.status
    const statusText = axiosError?.response?.statusText
    console.log('code', code)

    if (code === 401) {
      ctx.res.writeHead(302, {
        Location: `/login`,
      })
      ctx.res.end()
    }

    props = { code, statusText }
  }

  return { props }
}

withAxios 用法:

interface Props {
  data: any
}

export const getServerSideProps = withAxios<Props>(
  async ({ get, post }, ctx) => {
    const query = ctx.query
    console.log('query', query)
    const apiRes = await get('/api/xxx')
    return {
      data: apiRes.data,
    }
  }
)

export default (props: Props) => {
  // 避免服务端console
  useEffect(() => {
    console.log('data', props)
  }, [])
  return <MainLayout></MainLayout>
}