◆ 最初の POST のデータを変数に保存して トークン付きでリダイレクト
◆ トークンがあれば POST 時のデータを復元
◆ GET になるのでリダイレクト先は GET/POST 両方を受け取る必要あり
◆ 自動で POST するフォームの HTML レスポンスを返せば POST にできはする
◆ 抵抗のある方法だけど 一応外部サーバへのリダイレクトにも使える
◆ 外部にならプロキシとしてサーバが送信でいいと思う

普段とくにやらないのでほぼ困ってないのですが POST をリダイレクトしたら GET になって POST されないというのを見かけたので引き継がせてみました
サーバ言語は Node.js です
フレームワークに Koa を使ってますが仕組み的には何でも良いです

考え方

リダイレクトするときに一度サーバは POST でデータを受け取っています
なので それをサーバ上に保存しておいて 次の GET リクエストで復元します
次の GET リクエストで 「さっき POST したやつ」 が紐付けられるようにリダイレクト時には token をクエリパラメータにもたせます
token がクエリパラメータにある場合は紐づけた POST データを復元します
復元したらそのデータは消します
一時保存は Node.js だと変数が共有できるので変数上にしてます
その他言語だとファイルとかインメモリデータベースとかにすることになりそうです

コード

実際にやってみたものです
/ にフォームがあって /from へ POST します
/from は /to へリダイレクトします
/to では POST されたデータを表示します

const crypto = require("crypto")
const Koa = require("koa")
const Router = require("@koa/router")
const parse = require("koa-bodyparser")

const app = new Koa()
app.context.post_temp = new Map()

app.use(parse())
app.use((ctx, next) => {
if (ctx.query.oncetoken) {
const body = ctx.post_temp.get(ctx.query.oncetoken)
ctx.post_temp.delete(ctx.query.oncetoken)
ctx.request.body = body
}
return next()
})

const router = new Router()
router.get("/", ctx => {
ctx.body = `
<form action="/from" method="POST">
<input name="text">
<button>POST</button>
</form>
`
})
router.post("/from", ctx => {
const oncetoken = crypto.randomBytes(16).toString("hex")
ctx.post_temp.set(oncetoken, ctx.request.body)
ctx.redirect("/to?oncetoken=" + oncetoken)
})
router.register("/to", ["get", "post"], ctx => {
if (ctx.request.body) {
const text = ctx.request.body.text
const escaped = text.replace(/[<>&]/g, e => {
return {
"<": "&lt;",
">": "&gt;",
"&": "&amp;",
}[e]
})
ctx.body = `
<p>your text is <b>${escaped}</b>
`
} else {
ctx.body = "no data posted"
}
})
app.use(router.routes())

app.listen(4000)

制限

リダイレクトが GET になる以上 リダイレクト先は GET で受け取るしかありません
なので /to は GET と POST の両方を受け取るようにして POST データか復元された POST データがあれば POST とみなすようにしています

/from が HTTP のヘッダーによるリダイレクトでなく自動 POST のフォームでリダイレクトさせれば POST にはなりますけど ブラウザに依存し過ぎな上に自動で POST がなんか嫌なのでやってません
やるならこういうレスポンスを /from で返せばいいです

<form action="/to" method="POST">
<input type="hidden" name="text" value="${text}">
</form>

<script>
document.querySelector("form").submit()
</script>

本来の POST と同じように見せるためには それぞれのデータを元のフォームと同じようにを別の input に入れる必要があります
しかし それをやるのはデータ数が多いと form を作るのも大変です
楽にするなら name を元のものとは別にして restore という name で JSON 形式で全部の値を入れてしまい /to では restore という名前なら JSON から復元するようにするなどできます

必要?

作ってみましたが 実際に必要かと考えると別にいらないと思います
わざわざリダイレクトしないでも リダイレクト先がわかるならそこでやる処理をその場でやればいいです
ルートごとの処理を関数にわけていれば引数を調整して呼び出すだけで済みます
結果表示の URL にこだわりがあるなら history.replace でリダイレクト先に見せかければいいです

リダイレクト先が同じサーバじゃないというケースもなくはないです
その場合はリダイレクト先の処理の関数呼び出しも 今回のサーバ側でデータを保持する方法も使えません
一応自動 POST というイマイチな方法を使えばいけますけど
それするくらいならブラウザから POST させるんじゃなくて サーバが POST してそのレスポンスを返すプロキシのような動きでいい気がします