เฟรมเวิร์กมิดเดิลแวร์สำหรับเซิร์ฟเวอร์ HTTP ดั้งเดิมของ DENO, DENO DEPLOY, NODE.JS 16.5 และหลังจากนั้นคนงาน CloudFlare และ BUN นอกจากนี้ยังมีเราเตอร์มิดเดิลแวร์
เฟรมเวิร์กมิดเดิลแวร์นี้ได้รับแรงบันดาลใจจากเราเตอร์ KOA และมิดเดิลแวร์ที่ได้รับแรงบันดาลใจจาก @koa/เราเตอร์
readme นี้มุ่งเน้นไปที่กลไกของ Oak API และมีไว้สำหรับผู้ที่คุ้นเคยกับกรอบมิดเดิลแวร์ JavaScript เช่น Express และ KOA รวมถึงความเข้าใจที่ดีของ Deno หากคุณไม่คุ้นเคยกับสิ่งเหล่านี้โปรดตรวจสอบเอกสารเกี่ยวกับ Oakserver.github.io/oak
นอกจากนี้ตรวจสอบคำถามที่พบบ่อยของเราและเว็บไซต์ที่ยอดเยี่ยมของแหล่งข้อมูลชุมชน
บันทึก
ตัวอย่างในการดึง readme นี้จาก main และได้รับการออกแบบมาสำหรับการปรับใช้ deno CLI หรือ deno ซึ่งอาจไม่สมเหตุสมผลที่จะทำเมื่อคุณกำลังมองหาการปรับใช้ภาระงานจริง คุณต้องการที่จะ "ปักหมุด" เป็นเวอร์ชันเฉพาะที่เข้ากันได้กับเวอร์ชันของ DENO ที่คุณใช้และมีชุด API ที่แน่นอนที่คุณคาดหวัง https://deno.land/x/ รองรับการใช้แท็ก GIT ใน URL เพื่อนำคุณไปที่เวอร์ชันใดรุ่นหนึ่ง ดังนั้นในการใช้ Oak เวอร์ชัน 13.0.0 คุณจะต้องนำเข้า https://deno.land/x/[email protected]/mod.ts
Oak มีให้บริการทั้งใน deno.land/x และ jsr หากต้องการใช้จาก deno.land/x นำเข้าสู่โมดูล:
import { Application } from "https://deno.land/x/oak/mod.ts" ;หากต้องการใช้จาก JSR ให้นำเข้าสู่โมดูล:
import { Application } from "jsr:@oak/oak@14" ;OAK มีให้สำหรับ Node.js ทั้ง NPM และ JSR หากต้องการใช้จาก NPM ให้ติดตั้งแพ็คเกจ:
npm i @oakserver/oak@14
จากนั้นนำเข้าสู่โมดูล:
import { Application } from "@oakserver/oak" ;หากต้องการใช้จาก JSR ให้ติดตั้งแพ็คเกจ:
npx jsr i @oak/oak@14
จากนั้นนำเข้าสู่โมดูล:
import { Application } from "@oak/oak/application" ; บันทึก
ส่งการอัพเกรด WebSocket และให้บริการมากกว่า TLS/HTTPS ไม่ได้รับการสนับสนุนในปัจจุบัน
นอกจากนี้สภาพแวดล้อมของคนงาน CloudFlare และบริบทการดำเนินการยังไม่ได้สัมผัสกับมิดเดิลแวร์ในปัจจุบัน
Oak มีให้สำหรับคนงาน CloudFlare บน JSR หากต้องการใช้เพิ่มแพ็คเกจในโครงการ CloudFlare Worker ของคุณ:
npx jsr add @oak/oak@14
จากนั้นนำเข้าสู่โมดูล:
import { Application } from "@oak/oak/application" ;ซึ่งแตกต่างจากรันไทม์อื่น ๆ แอปพลิเคชันโอ๊คไม่ฟังคำขอที่เข้ามา แต่จะจัดการคำขอดึงข้อมูลของคนงาน เซิร์ฟเวอร์ตัวอย่างน้อยที่สุดคือ:
import { Application } from "@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( ( ctx ) => {
ctx . response . body = "Hello CFW!" ;
} ) ;
export default { fetch : app . fetch } ; บันทึก
ไม่รองรับการอัพเกรด Send และ WebSocket
Oak มีให้สำหรับ BUN บน JSR เพื่อใช้ติดตั้งแพ็คเกจ:
bunx jsr i @oak/oak@14
จากนั้นนำเข้าสู่โมดูล:
import { Application } from "@oak/oak/application" ; บันทึก
ไม่รองรับการอัพเกรด Send และ WebSocket
คลาส Application ชันพิกัดการจัดการเซิร์ฟเวอร์ HTTP ใช้มิดเดิลแวร์และการจัดการข้อผิดพลาดที่เกิดขึ้นเมื่อประมวลผลคำขอ โดยทั่วไปสองวิธีจะใช้: .use() และ .listen() มิดเดิลแวร์จะถูกเพิ่มผ่านวิธี .use() และเมธอด .listen() จะเริ่มต้นเซิร์ฟเวอร์และเริ่มคำขอการประมวลผลด้วยมิดเดิลแวร์ที่ลงทะเบียน
การใช้งานขั้นพื้นฐานตอบสนองต่อทุกคำขอกับ Hello World! -
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( ( ctx ) => {
ctx . response . body = "Hello World!" ;
} ) ;
await app . listen ( { port : 8000 } ) ;จากนั้นคุณจะเรียกใช้สคริปต์นี้ใน deno เช่น:
> deno run --allow-net helloWorld.ts
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการเรียกใช้รหัสภายใต้ DENO หรือข้อมูลเกี่ยวกับวิธีการติดตั้ง DENO CLI ให้ตรวจสอบคู่มือ DENO
มิดเดิลแวร์จะถูกประมวลผลเป็นสแต็กซึ่งฟังก์ชั่นมิดเดิลแวร์แต่ละตัวสามารถควบคุมการไหลของการตอบสนองได้ เมื่อมีการเรียกมิดเดิลแวร์มันจะถูกส่งผ่านบริบทและอ้างอิงถึงวิธี "ถัดไป" ในสแต็ก
ตัวอย่างที่ซับซ้อนมากขึ้น:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
// Logger
app . use ( async ( ctx , next ) => {
await next ( ) ;
const rt = ctx . response . headers . get ( "X-Response-Time" ) ;
console . log ( ` ${ ctx . request . method } ${ ctx . request . url } - ${ rt } ` ) ;
} ) ;
// Timing
app . use ( async ( ctx , next ) => {
const start = Date . now ( ) ;
await next ( ) ;
const ms = Date . now ( ) - start ;
ctx . response . headers . set ( "X-Response-Time" , ` ${ ms } ms` ) ;
} ) ;
// Hello World!
app . use ( ( ctx ) => {
ctx . response . body = "Hello World!" ;
} ) ;
await app . listen ( { port : 8000 } ) ; ในการจัดเตรียมเซิร์ฟเวอร์ HTTPS ตัวเลือก app.listen() จำเป็นต้องรวมตัวเลือกตัวเลือก .secure ตั้งค่าเป็น true และจัดหา .certFile และตัวเลือก .keyFile ด้วย
.handle() วิธีการ วิธี .handle() ใช้ในการประมวลผลคำขอและรับการตอบกลับโดยไม่ต้องมีแอปพลิเคชันจัดการด้านเซิร์ฟเวอร์ แม้ว่านี่คือการใช้งานขั้นสูงและผู้ใช้ส่วนใหญ่จะต้องการใช้ .listen()
วิธี .handle() ยอมรับอาร์กิวเมนต์สูงสุดสามข้อ ครั้งแรกที่เป็นอาร์กิวเมนต์ Request และข้อที่สองเป็นอาร์กิวเมนต์ Deno.Conn อาร์กิวเมนต์ตัวเลือกที่สามคือธงเพื่อระบุว่าคำขอนั้น "ปลอดภัย" ในแง่ที่เกิดจากการเชื่อมต่อ TLS ไปยังไคลเอนต์ระยะไกลหรือไม่ วิธีการแก้ไขด้วยวัตถุ Response หรือ undefined หาก ctx.respond === true
ตัวอย่าง:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( ( ctx ) => {
ctx . response . body = "Hello World!" ;
} ) ;
const listener = Deno . listen ( { hostname : "localhost" , port : 8000 } ) ;
for await ( const conn of listener ) {
( async ( ) => {
const requests = Deno . serveHttp ( conn ) ;
for await ( const { request , respondWith } of requests ) {
const response = await app . handle ( request , conn ) ;
if ( response ) {
respondWith ( response ) ;
}
}
} ) ;
}อินสแตนซ์ของแอปพลิเคชันมีคุณสมบัติบางอย่างเช่นกัน:
contextState - กำหนดวิธีที่ใช้ในการสร้างสถานะสำหรับบริบทใหม่ ค่าของ "clone" จะกำหนดสถานะเป็นโคลนของสถานะแอพ ค่าของ "prototype" หมายถึงสถานะของแอพจะถูกใช้เป็นต้นแบบของสถานะบริบท ค่าของ "alias" หมายความว่าสถานะของแอปพลิเคชันและสถานะของบริบทจะเป็นการอ้างอิงถึงวัตถุเดียวกัน ค่าของ "empty" จะเริ่มต้นสถานะของบริบทด้วยวัตถุที่ว่างเปล่า
.jsonBodyReplacer - ฟังก์ชั่นตัวแทนที่ตัวเลือกซึ่งจะนำไปใช้กับร่างกาย JSON เมื่อสร้างการตอบสนอง
.jsonBodyReviver - ฟังก์ชั่น reviver เสริมซึ่งจะนำไปใช้เมื่ออ่านร่างกาย JSON ตามคำขอ
.keys
กุญแจที่จะใช้เมื่อลงนามและตรวจสอบคุกกี้ ค่าสามารถตั้งค่าเป็นอาร์เรย์ของคีย์และอินสแตนซ์ของ KeyStack หรือวัตถุที่ให้อินเทอร์เฟซเดียวกันกับ KeyStack (เช่นอินสแตนซ์ของ keygrip) หากเพียงแค่ปุ่มผ่านคีย์โอ๊คจะจัดการคีย์ผ่าน KeyStack ซึ่งช่วยให้การหมุนของคีย์ง่ายโดยไม่ต้องมีการลงนามค่าข้อมูลอีกครั้ง
.proxy
ค่าเริ่มต้นนี้เป็น false แต่สามารถตั้งค่าผ่านตัวเลือกตัวสร้าง Application สิ่งนี้มีวัตถุประสงค์เพื่อระบุว่าแอปพลิเคชันอยู่เบื้องหลังพร็อกซีและจะใช้ X-Forwarded-Proto , X-Forwarded-Host และ X-Forwarded-For เมื่อประมวลผลคำขอซึ่งควรให้ข้อมูลที่แม่นยำยิ่งขึ้นเกี่ยวกับคำขอ
.state
บันทึกสถานะแอปพลิเคชันซึ่งสามารถพิมพ์ได้อย่างมากโดยการระบุอาร์กิวเมนต์ทั่วไปเมื่อสร้าง Application() หรืออนุมานโดยการผ่านวัตถุสถานะ (เช่น Application({ state }) )
บริบทที่ส่งผ่านไปยังมิดเดิลแวร์มีคุณสมบัติหลายประการ:
.app
การอ้างอิงถึง Application ที่เรียกใช้มิดเดิลแวร์นี้
.cookies
อินสแตนซ์ Cookies สำหรับบริบทนี้ซึ่งช่วยให้คุณอ่านและตั้งค่าคุกกี้
.request
วัตถุ Request ที่มีรายละเอียดเกี่ยวกับคำขอ
.respond
กำหนดว่าเมื่อมิดเดิลแวร์เสร็จสิ้นการประมวลผลแอปพลิเคชันควรส่ง .response ไปยังไคลเอนต์หรือไม่ หากเป็น true การตอบกลับจะถูกส่งและหาก false จะไม่ส่งการตอบกลับ ค่าเริ่มต้นเป็น true แต่วิธีการบางอย่างเช่น .upgrade() และ .sendEvents() จะตั้งค่าเป็น false
.response
วัตถุ Response ซึ่งจะใช้ในการจัดทำการตอบกลับที่ส่งกลับไปยังผู้ร้องขอ
.socket
สิ่งนี้จะ undefined หากการเชื่อมต่อไม่ได้รับการอัพเกรดเป็นซ็อกเก็ตเว็บ หากการเชื่อมต่อได้รับการอัพเกรดอินเตอร์เฟส .socket จะถูกตั้งค่า
.state
บันทึกสถานะแอปพลิเคชันซึ่งสามารถพิมพ์ได้อย่างมากโดยการระบุอาร์กิวเมนต์ทั่วไปเมื่อสร้าง Application() หรืออนุมานโดยการผ่านวัตถุสถานะ (เช่น Application({ state }) )
บริบทที่ส่งไปยังมิดเดิลแวร์มีวิธีการบางอย่าง:
.assert()
ทำให้การยืนยันซึ่งถ้าไม่เป็นความจริงโยน HTTPError ซึ่ง subclass ถูกระบุโดยอาร์กิวเมนต์ที่สองโดยมีข้อความเป็นอาร์กิวเมนต์ที่สาม
.send()
สตรีมไฟล์ไปยังไคลเอนต์ที่ร้องขอ ดูเนื้อหาคงที่ด้านล่างสำหรับข้อมูลเพิ่มเติม
.sendEvents()
แปลงการเชื่อมต่อปัจจุบันเป็นการตอบสนองเหตุการณ์เซิร์ฟเวอร์-ส่งและส่งคืน ServerSentEventTarget ที่มีการกำหนดเป้าหมายที่ข้อความและเหตุการณ์สามารถสตรีมไปยังไคลเอนต์ สิ่งนี้จะตั้งค่า .respond ตอบสนองเป็น false
.throw()
โยน HTTPError ซึ่ง subclass ถูกระบุโดยอาร์กิวเมนต์แรกโดยมีข้อความที่ถูกส่งผ่านเป็นครั้งที่สอง
.upgrade()
พยายามอัพเกรดการเชื่อมต่อไปยังการเชื่อมต่อเว็บซ็อกเก็ตและส่งคืนอินเทอร์เฟซ WebSocket OAK เวอร์ชันก่อนหน้านี้จะเป็นการแก้ไข Promise ด้วยช่องเสียบเว็บ std/ws
ซึ่งแตกต่างจากกรอบมิดเดิลแวร์อื่น ๆ context ไม่มีนามแฝงจำนวนมาก ข้อมูลเกี่ยวกับคำขอนั้นอยู่ใน .request เท่านั้นและข้อมูลเกี่ยวกับการตอบสนองจะอยู่ใน .response เท่านั้น
context.cookies Cookies อนุญาตให้เข้าถึงค่าของคุกกี้ในคำขอและอนุญาตให้ตั้งค่าคุกกี้ในการตอบกลับ มันยึดคุกกี้โดยอัตโนมัติหากคุณสมบัติ .keys ถูกตั้งค่าบนแอปพลิเคชัน เพราะ .cookies ใช้เว็บ Crypto APIs เพื่อลงนามและตรวจสอบคุกกี้และ API เหล่านั้นทำงานในแบบอะซิงโครนัส API คุกกี้ทำงานในแบบอะซิงโครนัส มีหลายวิธี:
.get(key: string, options?: CookieGetOptions): Promise<string | undefined>
ความพยายามที่จะดึงคุกกี้ออกจากคำขอและส่งคืนค่าของคุกกี้ตามคีย์ หากมีการตั้งค่าแอปพลิ .keys แล้วคุกกี้จะได้รับการตรวจสอบกับคุกกี้เวอร์ชันที่ลงนาม หากคุกกี้ถูกต้องสัญญาจะแก้ไขด้วยค่า หากไม่ถูกต้องลายเซ็นคุกกี้จะถูกตั้งค่าให้ลบในการตอบกลับ หากคุกกี้ไม่ได้ลงนามโดยคีย์ปัจจุบันมันจะถูกลาออกและเพิ่มลงในการตอบสนอง
.set(key: string, value: string, options?: CookieSetDeleteOptions): Promise<void>
จะตั้งค่าคุกกี้ในการตอบกลับตามคีย์ที่ให้ค่าและตัวเลือกใด ๆ หากมีการตั้งค่าแอปพลิ .keys แล้วคุกกี้จะได้รับการลงนามและลายเซ็นที่เพิ่มเข้ามาในการตอบสนอง เมื่อคีย์ได้รับการลงนามแบบอะซิงโครนัสให้รอวิธีการ .set()
context.request มีข้อมูลเกี่ยวกับคำขอ มันมีคุณสมบัติหลายอย่าง:
.body
วัตถุที่ให้การเข้าถึงเนื้อหาของคำขอ ดูรายละเอียดด้านล่างเกี่ยวกับการร้องขอ Body API
.hasBody
ตั้งค่าเป็น true หากคำขออาจมีร่างกายหรือ false หากไม่ได้ มันไม่ได้ตรวจสอบว่าร่างกายได้รับการสนับสนุนโดยตัวแยกวิเคราะห์ร่างกายในตัวหรือไม่
[! คำเตือน] นี่คือ API ที่ไม่น่าเชื่อถือ ใน HTTP/2 ในหลาย ๆ สถานการณ์คุณไม่สามารถระบุได้ว่าคำขอมีร่างกายหรือไม่เว้นแต่คุณจะพยายามอ่านร่างกายเนื่องจากลักษณะการสตรีมของ HTTP/2 จาก DENO 1.16.1 สำหรับ HTTP/1.1, DENO ยังสะท้อนถึงพฤติกรรมนั้น วิธีที่เชื่อถือได้เพียงอย่างเดียวในการพิจารณาว่าคำขอมีร่างกายหรือไม่คือพยายามอ่านร่างกาย
เป็นการดีที่สุดที่จะตรวจสอบว่าร่างกายอาจมีความหมายกับคุณด้วยวิธีการที่กำหนดหรือไม่จากนั้นพยายามอ่านและประมวลผลร่างกายหรือไม่หากมีความหมายในบริบทที่กำหนด ตัวอย่างเช่น GET and HEAD ไม่ควรมีร่างกาย แต่วิธีการเช่น DELETE และ OPTIONS อาจ มีร่างกายและควรมีการประมวลผลร่างกายอย่างมีเงื่อนไขหากมีความหมายต่อแอปพลิเคชันของคุณ
.headers
ส่วนหัวสำหรับการร้องขออินสแตนซ์ของ Headers
.method
สตริงที่แสดงถึงวิธี HTTP สำหรับคำขอ
.originalRequest
เลิกใช้แล้ว สิ่งนี้จะถูกลบออกในการเปิดตัวในอนาคตของต้นโอ๊ก
คำขอ "ดิบ" NativeServer ซึ่งเป็นนามธรรมเหนือวัตถุ Request DOM .originalRequest.request เป็นอินสแตนซ์ Request DOM ที่กำลังดำเนินการ โดยทั่วไปผู้ใช้ควรหลีกเลี่ยงการใช้สิ่งเหล่านี้
.secure
ทางลัดสำหรับ .protocol , ส่งคืน true ถ้า https เป็นอย่างอื่น false
.source
เมื่อรันภายใต้ deno, .source จะถูกตั้งค่าเป็น Request มาตรฐานเว็บต้นฉบับ เมื่อทำงานภายใต้ nodejs สิ่งนี้จะ undefined
.url
อินสแตนซ์ของ URL ซึ่งขึ้นอยู่กับ URL แบบเต็มสำหรับคำขอ นี่คือสถานที่ที่มีส่วนหนึ่งของ URL ที่เปิดเผยในส่วนที่เหลือของวัตถุคำขอ
และหลายวิธี:
.accepts(...types: string[])
เจรจาประเภทเนื้อหาที่สนับสนุนโดยคำขอสำหรับการตอบกลับ หากไม่มีประเภทเนื้อหาที่ผ่านมาวิธีการจะส่งกลับอาร์เรย์ที่จัดลำดับความสำคัญของประเภทเนื้อหาที่ยอมรับ หากมีการส่งเนื้อหาประเภทเนื้อหาการเจรจาต่อรองที่ดีที่สุด หากไม่มีการส่งคืนประเภทเนื้อหา undefined จะถูกส่งคืน
.acceptsEncodings(...encodings: string[])
เจรจาการเข้ารหัสเนื้อหาที่สนับสนุนโดยคำขอสำหรับการตอบกลับ หากไม่มีการเข้ารหัสผ่านวิธีการจะส่งกลับอาร์เรย์ที่จัดลำดับความสำคัญของการเข้ารหัสที่ยอมรับ หากผ่านการเข้ารหัสการเข้ารหัสการเจรจาต่อรองที่ดีที่สุดจะถูกส่งคืน หากไม่มีการเข้ารหัสที่ตรงกัน undefined จะถูกส่งคืน
.acceptsLanguages(...languages: string[])
เจรจาภาษาที่ลูกค้าสามารถเข้าใจได้ ในกรณีที่ตัวแปรสถานที่ตั้งค่าการตั้งค่า หากไม่มีการเข้ารหัสผ่านวิธีการจะส่งกลับอาร์เรย์ที่มีความสำคัญของภาษาที่เข้าใจ หากภาษาถูกส่งผ่านภาษาเจรจาที่ดีที่สุดจะถูกส่งคืน หากไม่มีการส่งคืนภาษา undefined
สำคัญ
API นี้เปลี่ยนไปอย่างมีนัยสำคัญใน Oak V13 และในภายหลัง API ก่อนหน้านี้เติบโตอย่างเป็นธรรมชาติตั้งแต่ต้นโอ๊กถูกสร้างขึ้นในปี 2561 และไม่ได้เป็นตัวแทน API ทั่วไปอื่น ๆ API ที่แนะนำใน V13 สอดคล้องกับวิธี Request ของ API ของ Fetch API ที่ดีกว่าและควรคุ้นเคยกับนักพัฒนาที่มาถึง Oak เป็นครั้งแรก
API สำหรับคำขอ OAK .body Body ได้รับแรงบันดาลใจจาก Request ของ Fetch API แต่มีฟังก์ชั่นเพิ่มบางอย่าง request.body บริบทของ Body เป็นอินสแตนซ์ของวัตถุที่มีคุณสมบัติหลายประการ:
.has
ตั้งค่าเป็น true หากคำขออาจมีร่างกายหรือ false หากไม่ได้ มันไม่ได้ตรวจสอบว่าร่างกายได้รับการสนับสนุนโดยตัวแยกวิเคราะห์ร่างกายในตัวหรือไม่
[! สำคัญ] นี่คือ API ที่ไม่น่าเชื่อถือ ใน HTTP/2 ในหลาย ๆ สถานการณ์คุณไม่สามารถระบุได้ว่าคำขอมีร่างกายหรือไม่เว้นแต่คุณจะพยายามอ่านร่างกายเนื่องจากลักษณะการสตรีมของ HTTP/2 จาก DENO 1.16.1 สำหรับ HTTP/1.1, DENO ยังสะท้อนถึงพฤติกรรมนั้น วิธีที่เชื่อถือได้เพียงอย่างเดียวในการพิจารณาว่าคำขอมีร่างกายหรือไม่คือพยายามอ่านร่างกาย
เป็นการดีที่สุดที่จะตรวจสอบว่าร่างกายอาจมีความหมายกับคุณด้วยวิธีการที่กำหนดหรือไม่จากนั้นพยายามอ่านและประมวลผลร่างกายหรือไม่หากมีความหมายในบริบทที่กำหนด ตัวอย่างเช่น GET and HEAD ไม่ควรมีร่างกาย แต่วิธีการเช่น DELETE และ OPTIONS อาจ มีร่างกายและควรมีการประมวลผลร่างกายอย่างมีเงื่อนไขหากมีความหมายต่อแอปพลิเคชันของคุณ
.stream
ReadableStream<Uint8Array> ที่จะช่วยให้การอ่านร่างกายใน Uint8Array ชิ้น นี่คือคุณสมบัติ .body ใน Request API Fetch
.used
ตั้งค่าเป็น true หากใช้ร่างกายแล้วตั้งค่าเป็น false
นอกจากนี้ยังมีหลายวิธี:
arrayBuffer()
แก้ไขด้วย ArrayBuffer ที่มีเนื้อหาของร่างกายถ้ามี เหมาะสำหรับการอ่าน/จัดการข้อมูลไบนารี
blob()
แก้ไขด้วย Blob ที่มีเนื้อหาของร่างกาย เหมาะสำหรับการอ่าน/จัดการข้อมูลไบนารี
form()
แก้ไขด้วย URLSearchParams ที่ได้รับการถอดรหัสจากเนื้อหาของร่างกาย สิ่งนี้เหมาะสำหรับร่างกายที่มีเนื้อหาประเภทของ application/x-www-form-urlencoded
formData()
แก้ไขด้วยอินสแตนซ์ FormData ซึ่งได้รับการถอดรหัสจากเนื้อหาของร่างกาย สิ่งนี้เหมาะสำหรับร่างกายที่มีเนื้อหาประเภทของ multipart/form-data
json()
แก้ไขด้วยข้อมูลจากร่างกายแยกวิเคราะห์เป็น JSON หากมีการระบุ jsonBodyReviver ในแอปพลิเคชันมันจะถูกใช้เมื่อแยกวิเคราะห์ JSON
text()
แก้ไขด้วยสตริงที่แสดงถึงเนื้อหาของร่างกาย
type()
ความพยายามที่จะให้คำแนะนำเกี่ยวกับวิธีการเข้ารหัสร่างกายซึ่งสามารถใช้เพื่อกำหนดวิธีการที่จะใช้ในการถอดรหัสร่างกาย วิธีการส่งคืนสตริงที่แสดงถึงประเภทของร่างกายที่ตีความ:
| ค่า | คำอธิบาย |
|---|---|
"binary" | ร่างกายมีประเภทเนื้อหาที่ระบุข้อมูลไบนารีและ .arrayBuffer() , .blob() หรือ .stream ควรใช้ในการอ่านร่างกาย |
"form" | ร่างกายถูกเข้ารหัสเป็นข้อมูลแบบฟอร์มและ .form() ควรใช้เพื่ออ่านร่างกาย |
"form-data" | ร่างกายถูกเข้ารหัสเป็นรูปแบบหลายส่วนและ .formData() ควรใช้ในการอ่านร่างกาย |
"json" | ร่างกายถูกเข้ารหัสเป็นข้อมูล JSON และ .json() ควรใช้ในการอ่านร่างกาย |
"text" | ควรใช้ร่างกายเป็นข้อความและ .text() ควรใช้เพื่ออ่านร่างกาย |
"unknown" | ไม่ว่าจะไม่มีร่างกายหรือเป็นไปไม่ได้ที่จะกำหนดประเภทของร่างกายตามประเภทเนื้อหา |
วิธี .type() ยังใช้อาร์กิวเมนต์เสริมของประเภทสื่อที่กำหนดเองที่จะใช้เมื่อพยายามกำหนดประเภทของร่างกาย สิ่งเหล่านี้จะรวมอยู่ในประเภทสื่อเริ่มต้น ค่าเป็นวัตถุที่คีย์เป็นหนึ่งใน binary form form-data , json หรือ text และค่าเป็นประเภทสื่อที่เหมาะสมในรูปแบบที่เข้ากันได้กับรูปแบบ Type-is
context.response มีข้อมูลเกี่ยวกับการตอบกลับซึ่งจะถูกส่งกลับไปยังผู้ร้องขอ มันมีคุณสมบัติหลายอย่าง:
.body
ร่างกายของการตอบสนองซึ่งมักจะได้รับการจัดการโดยการจัดการร่างกายการตอบสนองอัตโนมัติที่บันทึกไว้ด้านล่าง
.headers
อินสแตนซ์ส่วน Headers ซึ่งมีส่วนหัวสำหรับการตอบกลับ
.status
รหัส Status HTTP ที่จะส่งกลับพร้อมการตอบกลับ หากไม่ได้ตั้งค่าไว้ก่อนที่จะตอบสนอง OAK จะเริ่มต้น 200 OK หากมี .body 404 Not Found
.type
ประเภทสื่อหรือส่วนขยายเพื่อตั้งส่วนหัว Content-Type สำหรับการตอบกลับ ตัวอย่างเช่นคุณสามารถให้ txt หรือ text/plain เพื่ออธิบายร่างกาย
และหลายวิธี:
.redirect(url?: string | URL | REDIRECT_BACK, alt?: string | URL)
วิธีการที่จะทำให้การเปลี่ยนเส้นทางการตอบสนองไปยัง URL อื่นง่ายขึ้น มันจะตั้งค่าส่วนหัว Location เป็น url ที่ให้มาและสถานะเป็น 302 Found (เว้นแต่สถานะจะมีสถานะ 3XX อยู่แล้ว) การใช้สัญลักษณ์ REDIRECT_BACK เป็น url ระบุว่าส่วนหัว Referer ในคำขอควรใช้เป็นทิศทางโดยที่ alt เป็นตำแหน่งทางเลือกหากไม่ได้ตั้งค่า Referer หากไม่มีการตั้งค่า alt หรือ Referer การเปลี่ยนเส้นทางจะเกิดขึ้นกับ / HTML พื้นฐาน (หากผู้ร้องขอรองรับ) หรือตัวข้อความจะถูกตั้งค่าอธิบายว่าพวกเขากำลังถูกเปลี่ยนเส้นทาง
.toDomResponse()
สิ่งนี้แปลงข้อมูลโอ๊คเข้าใจเกี่ยวกับการตอบสนองต่อ Response API ของ Fetch สิ่งนี้จะเสร็จสิ้นการตอบสนองทำให้เกิดความพยายามเพิ่มเติมในการปรับเปลี่ยนการตอบสนองต่อการโยน สิ่งนี้มีวัตถุประสงค์เพื่อใช้ภายใน Oak เพื่อให้สามารถตอบสนองต่อคำขอได้
.with(response: Response) และ .with(body?: BodyInit, init?: ResponseInit)
สิ่งนี้ตั้งค่าการตอบสนองต่อ Response มาตรฐานเว็บ โปรดทราบว่าสิ่งนี้จะไม่สนใจ/แทนที่ข้อมูลอื่น ๆ ที่ตั้งไว้ในการตอบกลับโดยมิดเดิลแวร์อื่น ๆ รวมถึงสิ่งต่าง ๆ เช่นส่วนหัวหรือคุกกี้ที่จะตั้งค่า
เมื่อไม่ได้ตั้งค่า Content-Type ในส่วนหัวของ .response . OAK จะพยายามกำหนด Content-Type ที่เหมาะสมโดยอัตโนมัติ ก่อนอื่นจะดู. .response.type หากได้รับมอบหมายจะพยายามแก้ไขประเภทสื่อที่เหมาะสมตามการรักษาค่า .type เป็นประเภทสื่อหรือการแก้ไขประเภทสื่อตามส่วนขยาย ตัวอย่างเช่นถ้า .type ถูกตั้งค่าเป็น "html" ดังนั้น Content-Type จะถูกตั้งค่าเป็น "text/html"
หาก .type ไม่ได้ตั้งค่าด้วยค่าโอ๊คจะตรวจสอบค่า .response.body หากค่าเป็น string แล้วโอ๊คจะตรวจสอบเพื่อดูว่าสตริงดูเหมือน HTML หรือไม่ถ้าเป็นเช่นนั้น Content-Type จะถูกตั้งค่าเป็น text/html มิฉะนั้นจะถูกตั้งค่าเป็น text/plain หากค่าเป็นวัตถุนอกเหนือจาก Uint8Array , Deno.Reader หรือ null วัตถุจะถูกส่งผ่านไปยัง JSON.stringify() และ Content-Type จะถูกตั้งค่าเป็น application/json
หากประเภทของร่างกายเป็นตัวเลข, bigint หรือสัญลักษณ์มันจะถูกบังคับให้เข้ากับสตริงและถือว่าเป็นข้อความ
หากค่าของร่างกายเป็นฟังก์ชันฟังก์ชั่นจะถูกเรียกโดยไม่มีข้อโต้แย้ง หากค่าส่งคืนของฟังก์ชั่นเป็นสัญญาเช่นนั้นจะรออยู่และค่าที่ได้รับการแก้ไขจะถูกประมวลผลดังกล่าวข้างต้น หากค่าไม่ได้สัญญาเช่นนั้นจะถูกประมวลผลดังกล่าวข้างต้น
วิธีแอปพลิเคชัน .listen() ใช้เพื่อเปิดเซิร์ฟเวอร์เริ่มฟังคำขอและการประมวลผลมิดเดิลแวร์ที่ลงทะเบียนสำหรับแต่ละคำขอ วิธีนี้ส่งคืนสัญญาเมื่อเซิร์ฟเวอร์ปิด
เมื่อเซิร์ฟเวอร์เปิดอยู่ก่อนที่จะเริ่มการดำเนินการตามคำขอแอปพลิเคชันจะยิงเหตุการณ์ "listen" ซึ่งสามารถฟังได้ผ่านวิธี .addEventListener() ตัวอย่างเช่น:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . addEventListener ( "listen" , ( { hostname , port , secure } ) => {
console . log (
`Listening on: ${ secure ? "https://" : "http://" } ${
hostname ?? "localhost"
} : ${ port } ` ,
) ;
} ) ;
// register some middleware
await app . listen ( { port : 80 } ) ;หากคุณต้องการปิดแอปพลิเคชันแอปพลิเคชันรองรับตัวเลือกสัญญาณยกเลิก นี่คือตัวอย่างของการใช้สัญญาณ:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
const controller = new AbortController ( ) ;
const { signal } = controller ;
// Add some middleware using `app.use()`
const listenPromise = app . listen ( { port : 8000 , signal } ) ;
// In order to close the server...
controller . abort ( ) ;
// Listen will stop listening for requests and the promise will resolve...
await listenPromise ;
// and you can do something after the close to shutdownมิดเดิลแวร์สามารถใช้เพื่อจัดการกับข้อผิดพลาดอื่น ๆ ด้วยมิดเดิลแวร์ รอมิดเดิลแวร์อื่น ๆ เพื่อดำเนินการในขณะที่ข้อผิดพลาดกับดักทำงาน ดังนั้นหากคุณมีข้อผิดพลาดในการจัดการมิดเดิลแวร์ที่ให้การตอบสนองที่ดีต่อข้อผิดพลาดจะทำงานเช่นนี้:
import { Application } from "jsr:@oak/oak/application" ;
import { isHttpError } from "jsr:@oak/commons/http_errors" ;
import { Status } from "jsr:@oak/commons/status" ;
const app = new Application ( ) ;
app . use ( async ( ctx , next ) => {
try {
await next ( ) ;
} catch ( err ) {
if ( isHttpError ( err ) ) {
switch ( err . status ) {
case Status . NotFound :
// handle NotFound
break ;
default :
// handle other statuses
}
} else {
// rethrow if you can't handle the error
throw err ;
}
}
} ) ; ข้อยกเว้นมิดเดิลแวร์ที่ไม่ได้รับการยกเว้นจะถูกจับโดยแอปพลิเคชัน Application ขยาย EventTarget ทั่วโลกใน DENO และเมื่อเกิดข้อผิดพลาดที่ไม่ถูกต้องเกิดขึ้นในมิดเดิลแวร์หรือส่งคำตอบ EventError จะถูกส่งไปยังแอปพลิเคชัน หากต้องการฟังข้อผิดพลาดเหล่านี้คุณจะเพิ่มตัวจัดการเหตุการณ์ในอินสแตนซ์แอปพลิเคชัน:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . addEventListener ( "error" , ( evt ) => {
// Will log the thrown error to the console.
console . log ( evt . error ) ;
} ) ;
app . use ( ( ctx ) => {
// Will throw a 500 on every request.
ctx . throw ( 500 ) ;
} ) ;
await app . listen ( { port : 80 } ) ; คลาส Router สร้างมิดเดิลแวร์ซึ่งสามารถใช้กับ Application เพื่อเปิดใช้งานการกำหนดเส้นทางตามชื่อพา ธ ของคำขอ
ตัวอย่างต่อไปนี้ให้บริการ บริการ แผนที่ของหนังสือโดยที่ http://localhost:8000/book/ จะคืนหนังสืออาร์เรย์และ http://localhost:8000/book/1 จะคืนหนังสือด้วย ID "1" :
import { Application } from "jsr:@oak/oak/application" ;
import { Router } from "jsr:@oak/oak/router" ;
const books = new Map < string , any > ( ) ;
books . set ( "1" , {
id : "1" ,
title : "The Hound of the Baskervilles" ,
author : "Conan Doyle, Arthur" ,
} ) ;
const router = new Router ( ) ;
router
. get ( "/" , ( context ) => {
context . response . body = "Hello world!" ;
} )
. get ( "/book" , ( context ) => {
context . response . body = Array . from ( books . values ( ) ) ;
} )
. get ( "/book/:id" , ( context ) => {
if ( books . has ( context ?. params ?. id ) ) {
context . response . body = books . get ( context . params . id ) ;
}
} ) ;
const app = new Application ( ) ;
app . use ( router . routes ( ) ) ;
app . use ( router . allowedMethods ( ) ) ;
await app . listen ( { port : 8000 } ) ; เส้นทางที่ผ่านจะถูกแปลงเป็นนิพจน์ทั่วไปโดยใช้เส้นทางสู่การรีเจ็กซ์ซึ่งหมายถึงพารามิเตอร์ที่แสดงในรูปแบบจะถูกแปลง path-to-regexp มีการใช้งานขั้นสูงซึ่งสามารถสร้างรูปแบบที่ซับซ้อนซึ่งสามารถใช้สำหรับการจับคู่ ตรวจสอบเอกสารสำหรับไลบรารีนั้นหากคุณมีกรณีการใช้งานขั้นสูง
ในกรณีส่วนใหญ่ประเภทของ context.params จะถูกอนุมานโดยอัตโนมัติจากสตริงเทมเพลตเส้นทางผ่าน Magic TypeScript ในสถานการณ์ที่ซับซ้อนมากขึ้นสิ่งนี้อาจไม่ได้ผลลัพธ์ที่ถูกต้องอย่างไรก็ตาม ในกรณีนั้นคุณสามารถแทนที่ประเภทด้วย router.get<RouteParams> โดยที่ RouteParams เป็นประเภทที่ชัดเจนสำหรับ context.params params
รองรับเราเตอร์ทำรัง ตัวอย่างต่อไปนี้ตอบสนองต่อ http://localhost:8000/forums/oak/posts และ http://localhost:8000/forums/oak/posts/nested-routers
import { Application } from "jsr:@oak/oak/application" ;
import { Router } from "jsr:@oak/oak/router" ;
const posts = new Router ( )
. get ( "/" , ( ctx ) => {
ctx . response . body = `Forum: ${ ctx . params . forumId } ` ;
} )
. get ( "/:postId" , ( ctx ) => {
ctx . response . body =
`Forum: ${ ctx . params . forumId } , Post: ${ ctx . params . postId } ` ;
} ) ;
const forums = new Router ( ) . use (
"/forums/:forumId/posts" ,
posts . routes ( ) ,
posts . allowedMethods ( ) ,
) ;
await new Application ( ) . use ( forums . routes ( ) ) . listen ( { port : 8000 } ) ; ฟังก์ชั่น send() ได้รับการออกแบบมาเพื่อให้บริการเนื้อหาคงที่เป็นส่วนหนึ่งของฟังก์ชั่นมิดเดิลแวร์ ในการใช้งานที่ตรงไปตรงมามากที่สุดจะมีรูทและคำขอที่ให้กับฟังก์ชันจะได้รับการเติมเต็มด้วยไฟล์จากระบบไฟล์ท้องถิ่นที่สัมพันธ์กับรูทจากเส้นทางที่ร้องขอ
การใช้งานขั้นพื้นฐานจะมีลักษณะเช่นนี้:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( async ( context , next ) => {
try {
await context . send ( {
root : ` ${ Deno . cwd ( ) } /examples/static` ,
index : "index.html" ,
} ) ;
} catch {
await next ( ) ;
}
} ) ;
await app . listen ( { port : 8000 } ) ; send() สนับสนุนคุณสมบัติโดยอัตโนมัติเช่นการจัดหาส่วนหัว ETag และส่วนหัว Last-Modified ในการตอบสนองเช่นเดียวกับการประมวลผล If-None-Match และส่วนหัว If-Modified-Since จากการร้องขอ ซึ่งหมายความว่าเมื่อให้บริการเนื้อหาแบบคงที่ลูกค้าจะสามารถพึ่งพาสินทรัพย์เวอร์ชันที่แคชแทนการโหลดอีกครั้ง
วิธี send() รองรับการสร้างส่วนหัว ETag สำหรับสินทรัพย์คงที่โดยอัตโนมัติ ส่วนหัวอนุญาตให้ไคลเอนต์ตรวจสอบว่าจำเป็นต้องดาวน์โหลดสินทรัพย์อีกครั้งหรือไม่ แต่จะมีประโยชน์ในการคำนวณ ETag สำหรับสถานการณ์อื่น ๆ
มีฟังก์ชั่นมิดเดิลแวร์ที่ประเมิน context.reponse.body และกำหนดว่ามันสามารถสร้างส่วนหัว ETag สำหรับประเภทของร่างกายนั้นและถ้าเป็นเช่นนั้นจะตั้งส่วนหัว ETag ไว้ในการตอบสนอง การใช้งานขั้นพื้นฐานจะมีลักษณะเช่นนี้:
import { Application } from "jsr:@oak/oak/application" ;
import { factory } from "jsr:@oak/oak/etag" ;
const app = new Application ( ) ;
app . use ( factory ( ) ) ;
// ... other middleware for the applicationนอกจากนี้ยังมีฟังก์ชั่นที่ดึงเอนทิตีสำหรับบริบทที่กำหนดขึ้นอยู่กับสิ่งที่ตรรกะในการอ่านลงในหน่วยความจำซึ่งสามารถส่งผ่านไปยัง ETAG คำนวณซึ่งเป็นส่วนหนึ่งของไลบรารี DENO STD:
import { Application } from "jsr:@oak/oak/application" ;
import { getEntity } from "jsr:@oak/oak/etag" ;
import { calculate } from "jsr:@std/http/etag" ;
const app = new Application ( ) ;
// The context.response.body has already been set...
app . use ( async ( ctx ) => {
const entity = await getEntity ( ctx ) ;
if ( entity ) {
const etag = await calculate ( entity ) ;
}
} ) ; Deno.serve() การย้ายถิ่นฐาน หากคุณอพยพจาก Deno.serve() หรือการปรับรหัสที่ออกแบบมาสำหรับ Request และ Response ของเว็บมาตรฐานการดึงข้อมูลเว็บมีคุณสมบัติสองอย่างของ OAK เพื่อช่วย
ctx.request.source เมื่อรันภายใต้ Deno สิ่งนี้จะถูกตั้งค่าเป็น Request Fetch API ให้การเข้าถึงคำขอเดิมโดยตรง
ctx.response.with() วิธีนี้จะยอมรับ Response API แบบดึงข้อมูลหรือสร้างการตอบสนองใหม่ตาม BodyInit และ ResponseInit ที่ให้ไว้ สิ่งนี้จะเสร็จสิ้นการตอบสนองและไม่สนใจสิ่งใดที่อาจถูกตั้งค่าไว้ในการ .response ของต้นโอ๊ก
middleware/serve#serve() และ middelware/serve#route() เครื่องกำเนิดไฟฟ้ามิดเดิลแวร์สองตัวนี้สามารถใช้เพื่อปรับรหัสที่ทำงานได้มากขึ้นเช่น Deno.serve() ซึ่งจะให้ Request API ดึงข้อมูลและคาดว่าตัวจัดการจะแก้ไขด้วย Response API ของ Fetch
ตัวอย่างของการใช้ serve() กับ Application.prototype.use() :
import { Application } from "jsr:@oak/oak/application" ;
import { serve } from "jsr:@oak/oak/serve" ;
const app = new Application ( ) ;
app . use ( serve ( ( req , ctx ) => {
console . log ( req . url ) ;
return new Response ( "Hello world!" ) ;
} ) ) ;
app . listen ( ) ; และโซลูชันที่คล้ายกันทำงานกับ route() โดยที่บริบทมีข้อมูลเกี่ยวกับเราเตอร์เช่น params:
import { Application } from "jsr:@oak/oak/application" ;
import { Router } from "jsr:@oak/oak/router" ;
import { route } from "jsr:@oak/oak/serve" ;
const app = new Application ;
const router = new Router ( ) ;
router . get ( "/books/:id" , route ( ( req , ctx ) => {
console . log ( ctx . params . id ) ;
return Response . json ( { title : "hello world" , id : ctx . params . id } ) ;
} ) ) ;
app . use ( router . routes ( ) ) ;
app . listen ( ) ; mod.ts ส่งออกวัตถุที่มีชื่อว่า testing ซึ่งมียูทิลิตี้บางอย่างสำหรับการทดสอบมิดเดิลแวร์ของไม้โอ๊คที่คุณอาจสร้าง ดูการทดสอบกับ Oak สำหรับข้อมูลเพิ่มเติม
มีหลายโมดูลที่ดัดแปลงโดยตรงจากโมดูลอื่น ๆ พวกเขาเก็บรักษาใบอนุญาตและลิขสิทธิ์ของแต่ละบุคคลไว้ โมดูลทั้งหมดรวมถึงชุดที่ดัดแปลงโดยตรงจะได้รับใบอนุญาตภายใต้ใบอนุญาต MIT
งานเพิ่มเติมทั้งหมดคือลิขสิทธิ์ 2018 - 2024 The Oak Authors สงวนลิขสิทธิ์