Express กับ hapi เปรียบเทียบกันได้อย่างไร?


133

จากมุมมองของการออกแบบและพัฒนาเว็บแอปพลิเคชัน Express และ Hapi เปรียบเทียบกันได้อย่างไร สำหรับตัวอย่างพื้นฐานดูเหมือนว่าจะคล้ายกัน แต่ฉันสนใจที่จะเรียนรู้เพิ่มเติมเกี่ยวกับความแตกต่างที่สำคัญในโครงสร้างแอปพลิเคชันโดยรวม

ยกตัวอย่างเช่นเท่าที่ผมได้เรียนรู้ขั้นตอนที่ใช้แตกต่างกันกลไกการกำหนดเส้นทางที่ไม่ได้ใช้คำสั่งการลงทะเบียนเข้าบัญชีสามารถทำ lookups เร็วขึ้น แต่มี จำกัด เมื่อเทียบกับเอ็กซ์เพรส มีความแตกต่างที่สำคัญอื่น ๆ หรือไม่?

นอกจากนี้ยังมีบทความเกี่ยวกับการเลือกใช้ Hapi (มากกว่า Express) สำหรับการพัฒนาเว็บไซต์ npmjs.com ใหม่บทความนี้ระบุว่า "ระบบปลั๊กอินของ Hapi หมายความว่าเราสามารถแยกแง่มุมและบริการต่างๆของแอปพลิเคชันในรูปแบบที่อนุญาตให้ใช้ไมโครเซอร์วิสใน ในทางกลับกัน Express ต้องการการกำหนดค่าอีกเล็กน้อยเพื่อให้ได้ฟังก์ชันการทำงานเดียวกัน "หมายความว่าอย่างไร?

คำตอบ:


231

นี่เป็นคำถามใหญ่และต้องการคำตอบที่ยาวเพื่อให้สมบูรณ์ดังนั้นฉันจะพูดถึงความแตกต่างที่สำคัญที่สุดส่วนหนึ่ง ขออภัยที่ยังคงเป็นคำตอบที่ยาว

คล้ายกันยังไง?

คุณพูดถูกจริงๆเมื่อคุณพูดว่า:

สำหรับตัวอย่างพื้นฐานดูเหมือนจะคล้ายกัน

ทั้งสองเฟรมเวิร์กกำลังแก้ปัญหาพื้นฐานเดียวกัน: จัดเตรียม API ที่สะดวกสำหรับการสร้างเซิร์ฟเวอร์ HTTP ในโหนด กล่าวคือสะดวกกว่าการใช้httpโมดูลเนทีฟระดับล่างเพียงอย่างเดียว httpโมดูลสามารถทำทุกอย่างที่เราต้องการ แต่มันเป็นเรื่องน่าเบื่อที่จะเขียนโปรแกรมด้วย

เพื่อให้บรรลุเป้าหมายนี้ทั้งคู่ใช้แนวคิดที่มีอยู่ในเว็บเฟรมเวิร์กระดับสูงมาเป็นเวลานาน: การกำหนดเส้นทางตัวจัดการปลั๊กอินโมดูลการพิสูจน์ตัวตน พวกเขาอาจไม่ได้มีชื่อเหมือนกันเสมอไป แต่ก็เทียบเท่ากันโดยประมาณ

ตัวอย่างพื้นฐานส่วนใหญ่มีลักษณะดังนี้:

  • สร้างเส้นทาง
  • เรียกใช้ฟังก์ชันเมื่อมีการร้องขอเส้นทางเตรียมการตอบสนอง
  • ตอบกลับคำขอ

ด่วน:

app.get('/', function (req, res) {

    getSomeValue(function (obj) {

        res.json({an: 'object'});
    });
});

Hapi:

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        getSomeValue(function (obj) {

            reply(obj);
        });
    }
});

ความแตกต่างไม่ได้แหวกแนวตรงนี้ใช่ไหม แล้วทำไมต้องเลือกอันอื่น?

แตกต่างกันอย่างไร?

คำตอบง่ายๆคือ hapi มีมากกว่านั้นมากและทำอะไรได้มากกว่านอกกรอบ นั่นอาจไม่ชัดเจนเมื่อคุณดูตัวอย่างง่ายๆจากด้านบน ในความเป็นจริงนี่เป็นความตั้งใจ กรณีที่เรียบง่ายจะถูกทำให้เรียบง่าย ลองตรวจสอบความแตกต่างที่สำคัญบางประการ:

ปรัชญา

Express ตั้งใจให้น้อยที่สุด ด้วยการมอบ API ขนาดเล็กให้กับคุณโดยมีเพียงการปัดฝุ่นบาง ๆ ที่ด้านบนhttpคุณยังคงเป็นตัวของตัวเองอย่างมากในแง่ของการเพิ่มฟังก์ชันเพิ่มเติม หากคุณต้องการที่จะอ่านเนื้อความของการร้องขอเข้ามา (ค่อนข้างเป็นงานที่ร่วมกัน) คุณจำเป็นต้องติดตั้งโมดูลที่แยกต่างหาก หากคุณคาดว่าจะมีการส่งเนื้อหาประเภทต่างๆไปยังเส้นทางนั้นคุณต้องตรวจสอบไฟล์Content-typeส่วนหัวเพื่อตรวจสอบว่าเป็นประเภทใดและแยกวิเคราะห์ตามนั้น (form-data vs JSON vs multi-part เป็นต้น) โดยมักใช้โมดูลแยกกัน .

hapi มีชุดคุณลักษณะที่หลากหลายซึ่งมักเปิดเผยผ่านตัวเลือกการกำหนดค่าแทนที่จะต้องเขียนโค้ด ตัวอย่างเช่นหากเราต้องการตรวจสอบให้แน่ใจว่าเนื้อหาคำขอ (payload) ถูกอ่านลงในหน่วยความจำอย่างสมบูรณ์และแยกวิเคราะห์อย่างเหมาะสม (โดยอัตโนมัติตามประเภทเนื้อหา) ก่อนที่ตัวจัดการจะรันมันเป็นเพียงตัวเลือกง่ายๆ:

server.route({
    config: {
        payload: {
            output: 'data',
            parse: true
        }
    },
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        reply(request.payload);
    }
});

คุณสมบัติ

คุณจะต้องเปรียบเทียบเอกสาร API ของทั้งสองโครงการเพื่อดูว่า hapi มีชุดคุณลักษณะที่ใหญ่กว่า

hapi มีคุณสมบัติบางอย่างต่อไปนี้ในตัวที่ Express ไม่มี (เท่าที่ฉันรู้):

ความสามารถในการขยายและการแยกส่วน

hapi และ Express ไปเกี่ยวกับการขยายตัวในวิธีที่แตกต่างกันมาก ด้วย Express คุณมีฟังก์ชันมิดเดิลแวร์ ฟังก์ชันมิดเดิลแวร์เป็นเหมือนตัวกรองที่คุณซ้อนกันและคำขอทั้งหมดจะทำงานผ่านก่อนที่จะกดปุ่มตัวจัดการของคุณ

hapi มีวงจรชีวิตของคำขอและมีจุดขยายซึ่งเทียบได้กับฟังก์ชันมิดเดิลแวร์ แต่มีจุดที่กำหนดไว้หลายจุดในวงจรชีวิตของคำขอ

หนึ่งในเหตุผลที่ Walmart สร้าง hapi และหยุดใช้ Express คือความยุ่งยากในการแบ่งแอป Express ออกเป็นส่วน ๆ แยกจากกันและมีสมาชิกในทีมที่แตกต่างกันทำงานอย่างปลอดภัย ด้วยเหตุนี้พวกเขาจึงสร้างระบบปลั๊กอินใน hapi

ปลั๊กอินเป็นเหมือนแอปพลิเคชันย่อยคุณสามารถทำทุกอย่างที่ทำได้ในแอป hapi เพิ่มเส้นทางจุดขยายและอื่น ๆ ในปลั๊กอินคุณสามารถมั่นใจได้ว่าคุณจะไม่ทำลายส่วนอื่นของแอปพลิเคชันเนื่องจากคำสั่งของ การลงทะเบียนเส้นทางไม่สำคัญและคุณไม่สามารถสร้างเส้นทางที่ขัดแย้งกันได้ จากนั้นคุณสามารถรวมปลั๊กอินนี้เข้ากับเซิร์ฟเวอร์และปรับใช้งานได้

ระบบนิเวศ

เนื่องจาก Express ช่วยให้คุณออกนอกกรอบได้เพียงเล็กน้อยคุณจึงต้องมองออกไปข้างนอกเมื่อต้องการเพิ่มอะไรในโครงการของคุณ หลายครั้งที่ทำงานกับ hapi คุณลักษณะที่คุณต้องการมีอยู่ในตัวหรือมีโมดูลที่สร้างโดยทีมงานหลัก

มินิมอลฟังดูดี แต่ถ้าคุณกำลังสร้างแอปที่ใช้งานจริงอย่างจริงจังโอกาสที่คุณจะต้องการสิ่งเหล่านี้ทั้งหมดในที่สุด

ความปลอดภัย

hapi ได้รับการออกแบบโดยทีมงานที่ Walmart เพื่อใช้งานการจราจรในวัน Black Friday ดังนั้นความปลอดภัยและความมั่นคงจึงเป็นเรื่องสำคัญที่สุด ด้วยเหตุนี้เฟรมเวิร์กจึงทำสิ่งต่างๆมากมายเป็นพิเศษเช่นการ จำกัด ขนาดน้ำหนักบรรทุกที่เข้ามาเพื่อป้องกันไม่ให้หน่วยความจำกระบวนการของคุณหมด นอกจากนี้ยังมีตัวเลือกสำหรับสิ่งต่างๆเช่น max event loop delay หน่วยความจำ RSS สูงสุดที่ใช้และขนาดสูงสุดของ v8 heap ซึ่งเซิร์ฟเวอร์ของคุณจะตอบสนองด้วยการหมดเวลา 503 แทนที่จะหยุดทำงาน

สรุป

ประเมินพวกเขาทั้งตัวคุณเอง นึกถึงความต้องการของคุณและข้อใดในสองข้อที่ตอบโจทย์ข้อกังวลที่สุด แช่ตัวในสองชุมชน (IRC, Gitter, Github) ดูว่าคุณชอบอะไร อย่าเพิ่งเอาคำพูดของฉัน และแฮ็คอย่างมีความสุข!


การปฏิเสธความรับผิด: ฉันมีความลำเอียงในฐานะผู้เขียนหนังสือเกี่ยวกับ hapiและข้างต้นเป็นความคิดเห็นส่วนตัวของฉันเป็นส่วนใหญ่


7
Matt ขอขอบคุณสำหรับโพสต์ที่ครอบคลุมหัวข้อ "ความสามารถในการขยายและการแยกส่วน" และ "ความปลอดภัย" เป็นส่วนที่มีประโยชน์มากที่สุดสำหรับฉัน ฉันเดาว่าควรค่าแก่การกล่าวขวัญว่าระบบเส้นทางใหม่ใน Express 4 มีการปรับปรุงโมดูลาร์สำหรับแอปพลิเคชันย่อย
Ali Shakiba

1
คำตอบที่ดี Matt. นอกจากนี้เรายังสับสน b / w Hapi และ Express ข้อเสียเปรียบอย่างหนึ่งที่เราพบกับ Hapi คือไม่มีการสนับสนุนจากชุมชนที่กว้างขวางเท่ากับ Express และอาจเป็นปัญหาใหญ่หากเราติดขัดที่ไหนสักแห่ง ต้องการความคิดเห็นของคุณเกี่ยวกับเรื่องเดียวกัน
Aman Gupta

1
Express เป็นแบบทั่วไปในขณะที่ hapi เป็นองค์กรมากกว่าเล็กน้อย
windmaomao

1
@MattHarrison คำตอบที่ดีตอนนี้ฉันกำลังอ่านหนังสือของคุณเกี่ยวกับ Hapi มันเยี่ยมมาก ฉันกำลังจะพัฒนาตลาดใหม่สำหรับหนังสือโดยใช้ Hapi บนแบ็กเอนด์และ vue.js ที่ส่วนหน้าหลังจากคุ้นเคยกับ Hapi แล้วฉันต้องการเข้าร่วมในโครงการ Hapi อย่างจริงจัง
Humoyun Ahmad

1
@ Humoyun สุดยอด! โปรดทราบว่ามี hapi เวอร์ชันหลักใหม่ที่มีการเปลี่ยนแปลงหลายอย่างตั้งแต่ <= v16.0.0 ฉันกำลังผลิตซีรีส์ screencast ที่ออกแบบมาเพื่อให้ผู้คนได้เรียนรู้ v17: youtube.com/playlist?list=PLi303AVTbxaxqjaSWPg94nccYIfqNoCHz
Matt Harrison

54

องค์กรของฉันกำลังไปกับฮาปิ นี่คือเหตุผลที่เราชอบ

Hapi คือ:

  • ได้รับการสนับสนุนจากคณะสำคัญ ซึ่งหมายความว่าการสนับสนุนจากชุมชนจะแข็งแกร่งและมีให้คุณตลอดการเผยแพร่ในอนาคต เป็นเรื่องง่ายที่จะค้นหาผู้คนที่หลงใหลใน Hapi และมีแบบฝึกหัดดีๆอยู่ที่นั่น (แม้ว่าจะไม่มากและกว้างขวางเท่ากับบทช่วยสอน ExpressJs) ณ วันที่โพสต์นี้ npm และ Walmart ใช้ Hapi
  • สามารถอำนวยความสะดวกในการทำงานของทีมงานแบบกระจายที่ทำงานในส่วนต่างๆของบริการแบ็กเอนด์โดยไม่จำเป็นต้องมีความรู้ที่ครอบคลุมเกี่ยวกับพื้นผิว API ที่เหลือ (สถาปัตยกรรมปลั๊กอินของ Hapi เป็นสิ่งที่ดีเลิศของคุณภาพนี้)
  • ปล่อยให้เฟรมเวิร์กทำในสิ่งที่เฟรมควรจะทำ: กำหนดค่าสิ่งต่างๆ หลังจากนั้นกรอบควรจะมองไม่เห็นและอนุญาตให้นักพัฒนามุ่งเน้นพลังสร้างสรรค์ที่แท้จริงของพวกเขาในการสร้างตรรกะทางธุรกิจ หลังจากใช้ Hapi เป็นเวลาหนึ่งปีฉันรู้สึกว่า Hapi ทำได้สำเร็จ ฉันรู้สึกมีความสุข!

หากคุณต้องการได้ยินโดยตรงจาก Eran Hammer (ผู้นำของ Hapi)

ในช่วงสี่ปีที่ผ่านมา hapi กลายเป็นกรอบการทำงานสำหรับหลาย ๆ โครงการไม่ว่าจะเล็กหรือใหญ่ สิ่งที่ทำให้ hapi ไม่เหมือนใครคือความสามารถในการปรับขนาดไปสู่การใช้งานขนาดใหญ่และทีมขนาดใหญ่ เมื่อโครงการเติบโตขึ้นความซับซ้อนก็เช่นกัน - ความซับซ้อนทางวิศวกรรมและความซับซ้อนของกระบวนการ สถาปัตยกรรมและปรัชญาของ hapi จัดการกับความซับซ้อนที่เพิ่มขึ้นโดยไม่จำเป็นต้อง refactor รหัสอยู่ตลอดเวลา[อ่านเพิ่มเติม]

การเริ่มต้นใช้งาน Hapi จะไม่ง่ายเหมือน ExpressJ เพราะ Hapi ไม่ได้มี "พลังดารา" เหมือนกัน ... แต่เมื่อคุณสบายใจคุณจะได้รับไมล์สะสมจำนวนมาก ฉันใช้เวลาประมาณ 2 เดือนในฐานะแฮ็กเกอร์หน้าใหม่ที่ใช้ ExpressJ อย่างขาดความรับผิดชอบเป็นเวลาสองสามปี หากคุณเป็นนักพัฒนาแบ็กเอนด์ที่ช่ำชองคุณจะรู้วิธีอ่านเอกสารและคุณอาจไม่สังเกตเห็นสิ่งนี้ด้วยซ้ำ

พื้นที่ที่เอกสาร Hapi สามารถปรับปรุงได้ใน:

  1. วิธีพิสูจน์ตัวตนผู้ใช้และสร้างเซสชัน
  2. การจัดการคำขอข้ามแหล่งที่มา (CORS)
  3. การอัปโหลดไฟล์ (หลายส่วนเป็นกลุ่ม)

ฉันคิดว่าการพิสูจน์ตัวตนน่าจะเป็นส่วนที่ท้าทายที่สุดเพราะคุณต้องตัดสินใจว่าจะใช้กลยุทธ์การตรวจสอบสิทธิ์แบบใด (การพิสูจน์ตัวตนขั้นพื้นฐาน, คุกกี้, โทเค็น JWT, OAuth) แม้ว่าในทางเทคนิคจะไม่ใช่ปัญหาของ Hapi ที่ภูมิทัศน์ของเซสชัน / การรับรองความถูกต้องนั้นกระจัดกระจาย ... แต่ฉันหวังว่าพวกเขาจะให้การถือด้วยมือสำหรับสิ่งนี้ มันจะเพิ่มความสุขให้กับนักพัฒนาอย่างมาก

อีกสองอย่างที่เหลือไม่ได้ยากขนาดนั้นเอกสารสามารถเขียนได้ดีขึ้นเล็กน้อย


3

ข้อมูลโดยย่อเกี่ยวกับ Hapi หรือทำไมต้อง Hapi JS?

Hapi เป็นคอนฟิกูเรชันเป็นศูนย์กลางมีการตรวจสอบสิทธิ์และการอนุญาตที่สร้างไว้ในเฟรมเวิร์กเผยแพร่ในบรรยากาศที่ผ่านการทดสอบการต่อสู้และพิสูจน์แล้วว่าคุ้มค่าจริงๆโมดูลทั้งหมดมีการครอบคลุมการทดสอบ 100% มันลงทะเบียนสิ่งที่เป็นนามธรรมในระดับสูงสุดห่างจาก HTTP หลักที่สามารถเข็มทิศได้อย่างง่ายดาย ผ่านสถาปัตยกรรมปลั๊กอิน

Hapi เป็นตัวเลือกประสิทธิภาพที่ดีกว่า Hapi ใช้กลไกการกำหนดเส้นทางที่แตกต่างกันซึ่งสามารถค้นหาได้เร็วขึ้นและคำนึงถึงลำดับการลงทะเบียน อย่างไรก็ตามมันค่อนข้าง จำกัด เมื่อเทียบกับ Express และด้วยระบบปลั๊กอิน Hapi ทำให้สามารถแยกแง่มุมและบริการต่างๆที่จะช่วยแอปพลิเคชันได้หลายวิธีในอนาคต

การใช้

Hapi เป็นเฟรมเวิร์คที่ต้องการมากที่สุดเมื่อเทียบกับ Express Hapi ใช้เป็นหลักในการใช้งานระดับองค์กรขนาดใหญ่

สาเหตุสองประการที่นักพัฒนาไม่เลือก Express เมื่อสร้างแอปพลิเคชันระดับองค์กร ได้แก่ :

เส้นทางเขียนใน Express ยากกว่า

มิดเดิลแวร์ได้รับผลกระทบเกือบตลอดเวลา ทุกครั้งที่คุณกำหนดเส้นทางคุณต้องเขียนรหัสเป็นจำนวนมาก

Hapi จะเป็นตัวเลือกที่ดีที่สุดสำหรับนักพัฒนาที่ต้องการสร้าง RESTful API Hapi มีสถาปัตยกรรมไมโครเซอร์วิสและยังสามารถถ่ายโอนการควบคุมจากตัวจัดการเครื่องหนึ่งไปยังอีกเครื่องหนึ่งโดยพิจารณาจากพารามิเตอร์ ด้วยปลั๊กอิน Hapi คุณสามารถเพลิดเพลินกับระดับนามธรรมรอบ ๆ HTTP ได้มากขึ้นเนื่องจากคุณสามารถแบ่งตรรกะทางธุรกิจออกเป็นส่วน ๆ ที่จัดการได้ง่าย

ข้อดีอีกอย่างของ Hapi คือมีข้อความแสดงข้อผิดพลาดโดยละเอียดเมื่อคุณกำหนดค่าผิด Hapi ยังให้คุณกำหนดค่าขนาดการอัพโหลดไฟล์ของคุณตามค่าเริ่มต้น หากขนาดการอัปโหลดสูงสุดมี จำกัด คุณสามารถส่งข้อความแสดงข้อผิดพลาดไปยังผู้ใช้โดยระบุว่าขนาดไฟล์ใหญ่เกินไป วิธีนี้จะป้องกันเซิร์ฟเวอร์ของคุณไม่ให้ล่มเนื่องจากการอัปโหลดไฟล์จะไม่พยายามบัฟเฟอร์ไฟล์ทั้งหมดอีกต่อไป

  1. สิ่งที่คุณสามารถทำได้โดยใช้ express สามารถทำได้อย่างง่ายดายโดยใช้ hapi.js

  2. Hapi.js มีสไตล์มากและจัดระเบียบรหัสได้เป็นอย่างดี หากคุณเห็นว่ามันกำหนดเส้นทางอย่างไรและวางตรรกะหลักในคอนโทรลเลอร์คุณจะต้องหลงรักมันอย่างแน่นอน

  3. Hapi.js มีปลั๊กอินหลายตัวสำหรับ hapi.js อย่างเป็นทางการตั้งแต่การตรวจสอบสิทธิ์โทเค็นไปจนถึงการจัดการเซสชันและอื่น ๆ อีกมากมายซึ่งเป็นโฆษณาบน ไม่ได้หมายความว่าไม่สามารถใช้ npm แบบดั้งเดิมได้ แต่ทั้งหมดได้รับการสนับสนุนโดย hapi.js

  4. หากคุณเขียนโค้ดใน hapi.js โค้ดจะสามารถบำรุงรักษาได้มาก


"ถ้าคุณเห็นวิธีการกำหนดเส้นทางและวางตรรกะหลักในคอนโทรลเลอร์ ... " ฉันไม่เห็นตัวอย่างใด ๆ ในเอกสารประกอบที่แสดงการใช้คอนโทรลเลอร์ ตัวอย่างการกำหนดเส้นทางทั้งหมดใช้คุณสมบัติตัวจัดการซึ่งเป็นฟังก์ชัน ฉันเปรียบเทียบวิธีนี้กับสิ่งที่ Laravel (PHP framework) และ AdonisJs (Node.js framework) ใช้สำหรับการกำหนดเส้นทางซึ่งเราสามารถใช้คอนโทรลเลอร์ในการกำหนดเส้นทางได้ ฉันอาจพลาดบางส่วนของเอกสาร HAPI ที่แสดงการใช้ตัวควบคุมในการกำหนดเส้นทาง ดังนั้นหากมีคุณสมบัตินี้อยู่ก็จะเป็นการดีสำหรับฉันเพราะฉันคุ้นเคยกับการใช้คอนโทรลเลอร์เพื่อกำหนดเส้นทางใน Laravel
Lex Soft

1

ฉันเริ่มใช้ Hapi เมื่อไม่นานมานี้และฉันค่อนข้างพอใจกับมัน เหตุผลของฉันคือ

  1. ทดสอบได้ง่ายขึ้น ตัวอย่างเช่น:

    • server.inject ช่วยให้คุณสามารถเรียกใช้แอปและรับคำตอบโดยไม่ต้องเรียกใช้และฟัง
    • server.info ให้ปัจจุบัน uri พอร์ต ฯลฯ
    • server.settingsเข้าถึงการกำหนดค่าเช่นserver.settings.cacheรับผู้ให้บริการแคชปัจจุบัน
    • เมื่อมีข้อสงสัยให้ดูที่/testโฟลเดอร์สำหรับส่วนใด ๆ ของแอพหรือปลั๊กอินที่รองรับเพื่อดูคำแนะนำเกี่ยวกับวิธีการจำลอง / ทดสอบ / ต้นขั้วเป็นต้น
    • ความรู้สึกของฉันคือรูปแบบสถาปัตยกรรมของ hapi ช่วยให้คุณเชื่อถือได้ แต่ตรวจสอบได้เช่นปลั๊กอินของฉันลงทะเบียนหรือไม่ ฉันจะประกาศการพึ่งพาโมดูลได้อย่างไร?
  2. มันทำงานนอกกรอบเช่นการอัปโหลดไฟล์สตรีมย้อนกลับจากปลายทางเป็นต้น

  3. ปลั๊กอินที่จำเป็นจะได้รับการบำรุงรักษาพร้อมกับไลบรารีหลัก เช่นแม่แบบแยก , แคชฯลฯ ประโยชน์เพิ่มเป็นมาตรฐานการเข้ารหัสเดียวกันถูกนำมาใช้เจอสิ่งที่จำเป็น

  4. ข้อผิดพลาดที่มีเหตุผลและการจัดการข้อผิดพลาด Hapi ตรวจสอบตัวเลือกการกำหนดค่าและเก็บตารางเส้นทางภายในเพื่อป้องกันเส้นทางที่ซ้ำกัน สิ่งนี้มีประโยชน์มากในขณะที่เรียนรู้เนื่องจากข้อผิดพลาดจะเกิดขึ้นในช่วงต้นแทนที่จะเป็นพฤติกรรมที่ไม่คาดคิดซึ่งต้องมีการดีบัก


-1

อีกจุดหนึ่งที่ต้องเพิ่ม Hapi เริ่มรองรับการโทร 'http2' ตั้งแต่เวอร์ชัน 16 เป็นต้นไป (ถ้าฉันจำไม่ผิด) อย่างไรก็ตาม Express ยังไม่รองรับโมดูล 'http2' โดยตรงจนถึง express 4 แม้ว่าพวกเขาจะเปิดตัวคุณลักษณะนี้ในเวอร์ชันอัลฟาของ express 5


-2
'use strict';
const Hapi = require('hapi');
const Basic = require('hapi-auth-basic');
const server = new Hapi.Server();
server.connection({
    port: 2090,
    host: 'localhost'
});


var vorpal = require('vorpal')();
const chalk = vorpal.chalk;
var fs = require("fs");

var utenti = [{
        name: 'a',
        pass: 'b'
    },
    {
        name: 'c',
        pass: 'd'
    }
];

const users = {
    john: {
        username: 'john',
        password: 'secret',
        name: 'John Doe',
        id: '2133d32a'
    },
    paul: {
        username: 'paul',
        password: 'password',
        name: 'Paul Newman',
        id: '2133d32b'
    }
};

var messaggi = [{
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'ciao'
    },
    {
        destinazione: 'a',
        sorgente: 'c',
        messsaggio: 'addio'
    },
    {
        destinazione: 'c',
        sorgente: 'a',
        messsaggio: 'arrivederci'
    }
];

var login = '';
var loggato = false;

vorpal
    .command('login <name> <pass>')
    .description('Effettua il login al sistema')
    .action(function (args, callback) {
        loggato = false;
        utenti.forEach(element => {
            if ((element.name == args.name) && (element.pass == args.pass)) {
                loggato = true;
                login = args.name;
                console.log("Accesso effettuato");
            }
        });
        if (!loggato)
            console.log("Login e Password errati");
        callback();
    });

vorpal
    .command('leggi')
    .description('Leggi i messaggi ricevuti')
    .action(function (args, callback) {
        if (loggato) {
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == login;
            });

            estratti.forEach(element => {
                console.log("mittente : " + element.sorgente);
                console.log(chalk.red(element.messsaggio));
            });
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('invia <dest> "<messaggio>"')
    .description('Invia un messaggio ad un altro utente')
    .action(function (args, callback) {
        if (loggato) {
            var trovato = utenti.find(function (element) {
                return element.name == args.dest;
            });
            if (trovato != undefined) {
                messaggi.push({
                    destinazione: args.dest,
                    sorgente: login,
                    messsaggio: args.messaggio
                });
                console.log(messaggi);
            }
        } else {
            console.log("Devi prima loggarti");
        }
        callback();
    });

vorpal
    .command('crea <login> <pass>')
    .description('Crea un nuovo utente')
    .action(function (args, callback) {
        var trovato = utenti.find(function (element) {
            return element.name == args.login;
        });
        if (trovato == undefined) {
            utenti.push({
                name: args.login,
                pass: args.pass
            });
            console.log(utenti);
        }
        callback();
    });

vorpal
    .command('file leggi utenti')
    .description('Legge il file utenti')
    .action(function (args, callback) {
        var contents = fs.readFileSync("utenti.json");
        utenti = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi utenti')
    .description('Scrive il file utenti')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(utenti);
        fs.writeFile('utenti.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

vorpal
    .command('file leggi messaggi')
    .description('Legge il file messaggi')
    .action(function (args, callback) {
        var contents = fs.readFileSync("messaggi.json");
        messaggi = JSON.parse(contents);
        callback();
    });

vorpal
    .command('file scrivi messaggi')
    .description('Scrive il file messaggi')
    .action(function (args, callback) {
        var jsontostring = JSON.stringify(messaggi);
        fs.writeFile('messaggi.json', jsontostring, function (err) {
            if (err) {
                return console.error(err);
            }
        });
        callback();
    });

// leggi file , scrivi file

vorpal
    .delimiter(chalk.yellow('messaggi$'))
    .show();




const validate = function (request, username, password, callback) {
    loggato = false;


    utenti.forEach(element => {
        if ((element.name == username) && (element.pass == password)) {
            loggato = true;
            console.log("Accesso effettuato");
            return callback(null, true, {
                name: username
            })
        }
    });
    if (!loggato)
        return callback(null, false);
};

server.register(Basic, function (err) {
    if (err) {
        throw err;
    }
});

server.auth.strategy('simple', 'basic', {
    validateFunc: validate
});



server.route({
    method: 'GET',
    path: '/',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            reply('hello, ' + request.auth.credentials.name);
        }
    }
});

//route scrivere
server.route({
    method: 'POST',
    path: '/invia',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            //console.log("Received POST from " + request.payload.name + "; id=" + (request.payload.id || 'anon'));
            var payload = encodeURIComponent(request.payload)
            console.log(request.payload);
            console.log(request.payload.dest);
            console.log(request.payload.messaggio);
            messaggi.push({
                destinazione: request.payload.dest,
                sorgente: request.auth.credentials.name,
                messsaggio: request.payload.messaggio
            });
            var jsontostring = JSON.stringify(messaggi);
            fs.writeFile('messaggi.json', jsontostring, function (err) {
                if (err) {
                    return console.error(err);
                }
            });
            console.log(messaggi);
            reply(messaggi[messaggi.length - 1]);

        }
    }
});


//route leggere (json)
server.route({
    method: 'GET',
    path: '/messaggi',
    config: {
        auth: 'simple',
        handler: function (request, reply) {
            messaggi = fs.readFileSync("messaggi.json");
            var estratti = messaggi.filter(function (element) {
                return element.destinazione == request.auth.credentials.name;
            });
            var s = [];

            console.log(request.auth.credentials.name);
            console.log(estratti.length);
            estratti.forEach(element => {

                s.push(element);

                //fare l'array con stringify
                //s+="mittente : "+element.sorgente+": "+element.messsaggio+"\n";

            });
            var a = JSON.stringify(s);
            console.log(a);
            console.log(s);
            reply(a);
        }
    }
});



server.start(function () {
    console.log('Hapi is listening to ' + server.info.uri);
});

function EseguiSql(connection, sql, reply) {
    var rows = [];
    request = new Request(sql, function (err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
            console.log("Invio Reply")
            reply(rows);
        }
    });

    request.on('row', function (columns) {
        var row = {};
        columns.forEach(function (column) {
            row[column.metadata.colName] = column.value;
        });
        rows.push(row);
    });

    connection.execSql(request);
}

server.route({
    method: 'POST',
    path: '/query',
    handler: function (request, reply) {
        // Qui dovrebbe cercare i dati nel body e rispondere con la query eseguita
        var connection = new Connection(config);

        // Attempt to connect and execute queries if connection goes through
        connection.on('connect', function (err) {
            if (err) {
                console.log(err);
            } else {

                console.log('Connected');
                console.log(request.payload.sql);
                EseguiSql(connection, request.payload.sql, reply);
            }
        });

    }
});

server.connection({
    host: process.env.HOST || 'localhost',
    port: process.env.PORT || 8080
});

var config = {
    userName: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    server: process.env.DB_SERVER,
    options: {
        database: process.env.DB_NAME,
        encrypt: true
    }
}

ยินดีต้อนรับสู่ StackOverflow คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับคำตอบของคุณและความเกี่ยวข้องกับคำถามที่ OP โพสต์ได้อย่างไร
Szymon Maszke
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.