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

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

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

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

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

  • 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>

ลายป้องกัน

การเข้าถึงค่าของส่วนหัว 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 จะปรากฏเป็น 1 ค่าที่มีรหัสด้านบน

    หากต้องแยกค่าส่วนหัวโดยใช้เซมิโคลอนเป็นตัวคั่น ให้ใช้ 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>
    

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