Antipattern: เข้าถึงส่วนหัว HTTP ที่มีหลายค่าอย่างไม่ถูกต้องในพร็อกซี API

คุณกำลังดูเอกสารประกอบ Apigee Edge
ไปที่ เอกสารประกอบเกี่ยวกับ Apigee X.
ข้อมูล

ส่วนหัว HTTP เป็นคู่ค่าชื่อที่อนุญาตแอปพลิเคชันไคลเอ็นต์และบริการแบ็กเอนด์ เพื่อส่งข้อมูลเพิ่มเติมเกี่ยวกับคำขอและการตอบกลับตามลำดับ ตัวอย่างง่ายๆ มีดังนี้

  • ส่วนหัวของคำขอการให้สิทธิ์จะส่งข้อมูลเข้าสู่ระบบของผู้ใช้ไปยังเซิร์ฟเวอร์:
    Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
  • ส่วนหัว Content-Type แสดงประเภทของเนื้อหาคำขอ/การตอบกลับที่ส่ง
    Content-Type: application/json

ส่วนหัว HTTP สามารถมีได้หนึ่งค่าหรือมากกว่า ขึ้นอยู่กับค่า คำจำกัดความของช่องส่วนหัว ส่วนหัวที่มีหลายค่าจะมีค่าที่คั่นด้วยคอมมา ต่อไปนี้คือตัวอย่างของส่วนหัวที่มีหลายค่า

  • Cache-Control: no-cache, no-store, must-revalidate
  • Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
  • X-Forwarded-For: 10.125.5.30, 10.125.9.125

Apigee Edge ช่วยให้นักพัฒนาซอฟต์แวร์เข้าถึงส่วนหัวได้อย่างง่ายดาย ตัวแปรโฟลว์ ในนโยบาย Edge หรือขั้นตอนแบบมีเงื่อนไข รายการตัวแปรที่ใช้ได้มีดังนี้ เพื่อเข้าถึงคำขอหรือส่วนหัวการตอบกลับที่เฉพาะเจาะจงใน Edge

ตัวแปรโฟลว์:

  • message.header.header-name
  • request.header.header-name
  • response.header.header-name
  • message.header.header-name.N
  • request.header.header-name.N
  • response.header.header-name.N

ออบเจ็กต์ JavaScript

  • context.proxyRequest.headers.header-name
  • context.targetRequest.headers.header-name
  • context.proxyResponse.headers.header-name
  • context.targetResponse.headers.header-name

ต่อไปนี้คือตัวอย่างนโยบาย AssignMessage ที่แสดงวิธีอ่านค่าของส่วนหัวของคำขอและจัดเก็บลงในตัวแปร

<AssignMessage continueOnError="false" enabled="true" name="assign-message-default">
  <AssignVariable>
    <Name>reqUserAgent</Name>
    <Ref>request.header.User-Agent</Ref>
  </AssignVariable>
</AssignMessage>

ลาย Antipattern

การเข้าถึงค่าของส่วนหัว HTTP ในนโยบาย Edge ในลักษณะที่แสดงผลเฉพาะค่าแรก ไม่ถูกต้องและอาจทำให้เกิดปัญหาได้หากส่วนหัว HTTP ที่เจาะจงมีค่ามากกว่า 1 ค่า

ส่วนต่อไปนี้จะมีตัวอย่างการเข้าถึงส่วนหัว

ตัวอย่างที่ 1: อ่านส่วนหัว "ยอมรับ" ที่มีหลายค่าโดยใช้โค้ด JavaScript

พิจารณาว่าส่วนหัว Accept มีหลายค่าตามที่แสดงด้านล่าง

Accept: text/html, application/xhtml+xml, application/xml

นี่คือโค้ด JavaScript ที่อ่านค่าจากส่วนหัว Accept

// Read the values from Accept header
var acceptHeaderValues = context.getVariable("request.header.Accept");

โค้ด JavaScript ด้านบนจะแสดงเฉพาะค่าแรกจากส่วนหัว Accept เช่น text/html

ตัวอย่างที่ 2: อ่านส่วนหัว Access-Control-Allow-Headers ที่มีหลายค่าในนโยบาย AssignMessage หรือ RaiseFault

พิจารณาว่าส่วนหัว Access-Control-Allow-Headers มีหลายค่าตามที่แสดงด้านล่าง

Access-Control-Allow-Headers: content-type, authorization

นี่คือส่วนของโค้ดจากนโยบาย AssignMessage หรือ RaiseFault ที่ตั้งค่าส่วนหัว Access-Control-Allow-Headers:

<Set>
  <Headers>
    <Header name="Access-Control-Allow-Headers">{request.header.Access-Control-Request-Headers}</Header>
  </Headers>
</Set>

โค้ดด้านบนจะกำหนดส่วนหัว Access-Control-Allow-Headers ด้วยค่าแรกจาก ส่วนหัวคำขอ Access-Control-Allow-Headers ในตัวอย่างนี้คือ content-type

ผลกระทบ

  1. ในทั้ง 2 ตัวอย่างข้างต้น จะเห็นเฉพาะค่าแรกจากส่วนหัวที่มีหลายค่าเท่านั้น หากมีการใช้ค่าเหล่านี้ในภายหลังโดยนโยบายอื่นในขั้นตอนของพร็อกซี API หรือโดยบริการแบ็กเอนด์ ดำเนินการฟังก์ชันหรือตรรกะ แล้วอาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิด
  2. เมื่อมีการเข้าถึงและส่งต่อค่าส่วนหัวของคำขอไปยังเซิร์ฟเวอร์เป้าหมาย คำขอ API อาจมีลักษณะดังนี้ ประมวลผลโดยแบ็กเอนด์อย่างไม่ถูกต้อง ซึ่งอาจให้ผลลัพธ์ที่ไม่ถูกต้อง
  3. หากแอปพลิเคชันไคลเอ็นต์ต้องใช้ค่าส่วนหัวที่ระบุจากการตอบกลับ Edge อาจประมวลผลไม่ถูกต้องและให้ผลลัพธ์ที่ไม่ถูกต้อง

แนวทางปฏิบัติแนะนำ

  1. ใช้ตัวแปรโฟลว์ในตัวที่เหมาะสม: request.header.header_name.values.count, request.header.header_name.N response.header.header_name.values.count response.header.header_name.N

    จากนั้นทำซ้ำเพื่อดึงค่าทั้งหมดจากส่วนหัวหนึ่งๆ ในนโยบายคำขอราคาเสนอ JavaScript หรือ Java

    ตัวอย่าง: ตัวอย่างโค้ด JavaScript เพื่ออ่านส่วนหัวที่มีหลายค่า

    for (var i = 1; i <=context.getVariable('request.header.Accept.values.count'); i++)
    {
      print(context.getVariable('request.header.Accept.' + i));
    }
    

    ตัวอย่างเช่น application/xml;q=0.9, */*;q=0.8 จะปรากฏเป็นค่าหนึ่งพร้อมโค้ดด้านบน

    หากต้องการแยกค่าส่วนหัวโดยใช้เซมิโคลอนเป็นตัวคั่น ให้ใช้ string.split(";") เพื่อแยกข้อมูลเหล่านี้ออกเป็นมูลค่า

  2. ใช้ฟังก์ชัน substring() ในตัวแปรโฟลว์ request.header.header_name.values ในนโยบาย RaiseFault หรือ AssignMessage เพื่ออ่านค่าทั้งหมดของส่วนหัวที่เฉพาะเจาะจง

    ตัวอย่าง: ตัวอย่างนโยบาย RaiseFault หรือ AssignMessage เพื่ออ่านส่วนหัวที่มีหลายค่า

    <Set>
      <Headers>
       <Header name="Access-Control-Allow-Headers">{substring(request.header.Access-Control-Request-Headers.values,1,-1)}</Header>
      </Headers>
    </Set>
    

อ่านเพิ่มเติม