feat(wordaddin): serve manifest with automatic origin rewrite
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 3s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 1m7s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 4s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 3s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 1m7s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 4s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
manifest ของ add-in เดิมเป็น static ใน public/ ฝัง URL dev (localhost:3000) ทั้งไฟล์ — deploy จริงต้อง rewrite มือเองทุกครั้ง ก่อนนำไป sideload ใน Word ตอนนี้ serve ผ่าน route แทน: app/wordaddin/manifest.xml/route.ts อ่าน template (public/wordaddin/manifest.template.xml — ย้ายจาก manifest.xml ด้วย git mv) แล้วเขียนทับ origin ให้ตรงโฮสต์ที่ขอ ไฟล์ — dev/UAT/production ดาวน์โหลด manifest.xml ขอ environment ตัวเองแล้ว sideload ได้ทันที - ถอด requestOrigin จาก N10 route เป็น utils/request-origin.ts ใช้ร่วม + เพิ่ม heuristic: โฮสต์ไม่ใช่ localhost + proto http = บังคับ https (Office รับ https เท่านั้น และ hop ภายในหลัง IIS เป็น http เสมอ — Next server ก็ฉีด x-forwarded-proto เอง จึง ชี้ขาดจากโฮสต์ปลายทาง ไม่เดาว่า header มาจาก proxy หรือถูกฉีด) deep link ของ N10 ได้พฤติกรรมเดียวกันเป็นผลพวง - ตรวจ nft trace แล้ว template ถูกดึงเข้า standalone ด้วย (คู่ กับ COPY public จาก commit ก่อน = ชัวร์สองชั้น) ยืนยัน: tsc + vitest 215 tests ผ่าน · ทดสอบบน dev server ด้วย curl 3 โหมด — direct ได้ http://localhost:3000 (Word ยกเว้น localhost), ผ่าน proxy ส่ง header ครบได้ https://<โฮสต์>, ผ่าน proxy ไม่ส่ง proto (กรณี IIS) ได้ https://<โฮสต์> จากการ bump · next build compile route ผ่าน (ขั้น standalone symlink พังเฉพาะเครื่อง local Windows สิทธิ์ symlink — ไม่เกี่ยวกับโค้ด Docker build ผ่าน) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
808233191d
commit
4bcd01a95f
6 changed files with 87 additions and 21 deletions
41
utils/request-origin.ts
Normal file
41
utils/request-origin.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// origin เต็มของ request ที่เข้ามา — ใช้ประกอบ URL เต็มที่จะส่งกลับออกไปข้างนอก
|
||||
// (deep link ของ N10 / manifest.xml ของ wordaddin) เพราะ request ที่เห็นฝั่ง app
|
||||
// มักผ่าน reverse proxy หลัง (IIS ของทางศาล) จึงต้องดู header ของ proxy ก่อน
|
||||
//
|
||||
// ถอดมาจาก requestOrigin เดิมใน app/api/note/external/documents/route.ts
|
||||
// (2026-10-16) ให้ route manifest ของ wordaddin ใช้ร่วม
|
||||
|
||||
/** origin เต็มของ request นี้: เชื่อ header ของ reverse proxy ก่อน
|
||||
* (x-forwarded-proto / x-forwarded-host — proxy หลายชั้นส่งเป็น comma list
|
||||
* ใช้ค่าแรก) แล้วค่อย fallback จาก host/protocol ของ request ตรง ๆ
|
||||
*
|
||||
* แล้วบังคับ https เมื่อโฮสต์ปลายทางไม่ใช่ localhost แต่ได้ proto เป็น http:
|
||||
* hop ภายในหลัง proxy เป็น http ปกติ (อาจไม่มี x-forwarded-proto ให้ — Next
|
||||
* server ก็ฉีด `x-forwarded-proto: http` ให้เองด้วย เชื่อ "ใครเป็นคนตั้ง" ไม่ได้)
|
||||
* ส่วนผู้บริโภค URL พวกนี้ (Word สำหรับ manifest — รับ https เท่านั้น ยกเว้น
|
||||
* localhost, browser สำหรับ deep link ของ N10) เข้าถึงโฮสต์จริงผ่าน https
|
||||
* เสมอ — ค่า http://<โฮสต์ที่ไม่ใช่ localhost> ใช้ไม่ได้จริง จึงชี้ขาดจากตัว
|
||||
* โฮสต์ปลายทางแทนการเดาว่า header มาจาก proxy หรือถูกฉีด */
|
||||
export function requestOrigin(req: Request): string {
|
||||
const url = new URL(req.url);
|
||||
const host =
|
||||
req.headers.get("x-forwarded-host")?.split(",")[0]?.trim() ??
|
||||
req.headers.get("host") ??
|
||||
url.host;
|
||||
const forwardedProto =
|
||||
req.headers.get("x-forwarded-proto")?.split(",")[0]?.trim() ??
|
||||
url.protocol.replace(":", "");
|
||||
// host อาจติด port มาด้วย (localhost:3000) — ถอดออกก่อนเทียบ (URL จัดการ
|
||||
// IPv6 ในวงเล็บ [::1] ให้ด้วย เขียน split(":") เองจะพัง)
|
||||
const hostname = (() => {
|
||||
try {
|
||||
return new URL(`http://${host}`).hostname;
|
||||
} catch {
|
||||
return host;
|
||||
}
|
||||
})();
|
||||
const isLocal =
|
||||
hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
|
||||
const proto = !isLocal && forwardedProto === "http" ? "https" : forwardedProto;
|
||||
return `${proto}://${host}`;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue