// ตัวอย่างรองรับค่าจาก Frontend ที่เป็น Vanilla JavaScript และ Classic Framework // โดย ผ่าน Form หรือ การกดลิงค์(GET) เปลี่ยนหน้าเพื่อดาว์นโหลดไฟล์ // จะมีข้อมูล info.ticket_data ที่สมบูรณ์แล้ว({fid,tid,uid,uname})แล้วเเรียก /api/template/generate เพื่อสร้างเอกสาร docx import { NextRequest, NextResponse } from 'next/server'; import path from 'path'; import fs from 'fs/promises'; const DOCEDIT_BASE_URL = process.env.DOCEDIT_BASE_URL??""; const EXTERNAL_API_KEY = process.env.EXTERNAL_API_KEY??""; const TMPL_PATH = process.env.TMPL_PATH??""; if (!DOCEDIT_BASE_URL||!EXTERNAL_API_KEY||!TMPL_PATH) { console.error('Missing variable DOCEDIT_BASE_URL, EXTERNAL_API_KEY or TMPL_PATH') } // console.log("download-docx env",DOCEDIT_BASE_URL,EXTERNAL_API_KEY,TMPL_PATH) async function processRequest(fid: string,tid:string,uid:string,uname:string):Promise> { // console.log("processRequest get:",fid,tid,uid,uname) // console.log(process.cwd()) const filePath = path.join(TMPL_PATH,`${fid}.json`); try { if (!fid||!tid||!uid||!uname) { return NextResponse.json({ error: 'Missing fid, tid, uid or uname' }, { status: 400 }); } // อ่านไฟล์ JSON จำลองการอ่านจากฐานข้อมูล const rawJson = await fs.readFile(filePath, 'utf-8'); const jsonData = JSON.parse(rawJson); if (!jsonData || typeof jsonData !== 'object' ) { return NextResponse.json({error:'Invalid data format'}, { status: 400 }); } //!! ตรวจสอบสิทธิ์ผู้ใช้ uid ว่ามีสิทธิ์เข้าถึงไฟล์ fid หรือไม่เพื่อกันการการยิง API ตรงๆ ไม่ผ่าน Frontend!! // ข้อมูลจำเป็นต้องมี prop นี้เสมอถ้าไม่มีให้สร้าง jsonData.info.ticket_data if(!Object.hasOwn(jsonData, 'info')) jsonData['info']={} jsonData.info['ticket_data'] = JSON.stringify({fid,tid,uid,uname}) // sign เองตรงนี้ให้อยู่ในรูปแบบ data.info={ticket_data,HmacSha256,Ed25519} หรือว่างไว้ให้ docedit สร้างให้ //ยิงไปหาระบบ Docedit เพื่อเอา Stream // console.log(`fetch ${DOCEDIT_BASE_URL}/api/template/generate`) const docxResponse = await fetch(`${DOCEDIT_BASE_URL}/api/template/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': EXTERNAL_API_KEY, }, body: JSON.stringify(jsonData), }); // เช็ค Content-Type และ Status ก่อน const contentType = docxResponse.headers.get('content-type') || ''; if (!docxResponse.ok || contentType.includes('text/html')) { const errorText = await docxResponse.text(); console.error('download-docx:Invalid docx Response:', errorText); return NextResponse.json( {error:`Error from docedit generate: Expected docx stream but received ${contentType} (Status ${docxResponse.status})`}, { status: 502 } ); } // 2. ดึง ReadableStream โดยตรงจาก Response ของระบบ const stream = docxResponse.body; // 3. ส่ง Binary Stream กลับไปยัง Browser พร้อม Header กำหนดประเภทไฟล์ const download_file = `${fid}_${uid}_xxx` return new NextResponse(stream as unknown as BodyInit, { status: 200, headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'Content-Disposition': `attachment; filename="${encodeURIComponent(download_file)}.docx"`, 'Cache-Control': 'no-store, max-age=0', }, }); } catch (error:any) { if ( error.code === 'ENOENT') { return NextResponse.json( { error: `Data not found: ${filePath}`}, { status: 404 } ); } console.error(error) return NextResponse.json({error:'Internal Server Error'}, { status: 500 }); } } export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const fid = searchParams.get('fid') || ''; const tid = searchParams.get('tid') || ''; const uid = searchParams.get('uid') || ''; const uname = searchParams.get('uname') || ''; return await processRequest(fid,tid,uid,uname) } export async function POST(request: NextRequest) { const formData = await request.formData(); const fid = String(formData.get('fid')) const tid = String(formData.get('tid')) const uid = String(formData.get('uid')) const uname = String(formData.get('uname')) return await processRequest(fid,tid,uid,uname) }