ExternalCallout policy

מדיניות רגילה

הדף הזה רלוונטי ל-Apigee ול-Apigee Hybrid.

לעיון במסמכי התיעוד של Apigee Edge

המדיניות ExternalCallout מאפשרת לשלוח בקשות gRPC לשרת gRPC כדי להטמיע התנהגות מותאמת אישית שלא נתמכת על ידי מדיניות Apigee. בקוד של השרת, אפשר לגשת בקלות למשתני זרימה ולשנות אותם בזרימה של proxy.

‫Apigee מתקשר עם שרת gRPC באמצעות מדיניות ExternalCallout דרך API. ‫Apigee משתמש ב-API כדי לשלוח משתני זרימה לשרת gRPC. בשרת gRPC, אפשר לקרוא את משתני הזרימה שמפורטים בדף העיון משתני זרימה, וגם משתנים נוספים שאתם מציינים ב-XML של המדיניות. אפשר גם לשנות את משתני הזרימה, בהתאם למשתנה.

אם מגדירים את שרת ה-gRPC באמצעות Apigee וכוללים את המדיניות הזו בשרת proxy, ‏ Apigee יטפל בבקשות API באופן הבא:

  1. ‫Apigee שולח הודעה שמכילה את משתני התהליך לשרת ה-gRPC.
  2. קוד השרת של gRPC מופעל, והוא ניגש למשתנים ומשנה אותם בהתאם להגדרות בקוד. לאחר מכן, שרת ה-gRPC שולח תגובה שמכילה את כל משתני התהליך בחזרה אל Apigee.
  3. ‫Apigee קורא את התגובה משרת ה-gRPC. אם נוספו משתנים או שמשתני זרימה שניתנים לשינוי שונו, הם מתעדכנים ב-Apigee.

המדיניות הזו היא מדיניות רגילה ואפשר לפרוס אותה בכל סוג של סביבה. מידע על סוגי המדיניות והזמינות שלהם בכל סוג סביבה זמין במאמר סוגי מדיניות.

מידע נוסף על שליחת בקשות gRPC זמין במאמרים הבאים:

<ExternalCallout>

מגדיר מדיניות ExternalCallout.

<ExternalCallout async="true" continueOnError="true" enabled="true" name="EC">

לרכיב הזה יש את המאפיינים הבאים שמשותפים לכל המדיניות:

מאפיין ברירת מחדל חובה? תיאור
name לא רלוונטי חובה

השם הפנימי של המדיניות. הערך של מאפיין name יכול להכיל אותיות, מספרים, רווחים, מקפים, קווים תחתונים ונקודות. הערך הזה לא יכול להיות ארוך מ-255 תווים.

אפשר להשתמש ברכיב <DisplayName> כדי לתת למדיניות תווית בשם אחר בשפה טבעית בכלי לעריכת פרוקסי בממשק המשתמש לניהול.

continueOnError FALSE אופציונלי מגדירים את הערך false כדי להחזיר שגיאה אם המדיניות נכשלת. זו התנהגות צפויה ברוב המקרים. הגדרה ל-true מאפשרת להמשיך את הביצוע של התהליך גם אחרי שמדיניות נכשלת. מאמרים קשורים:
enabled TRUE אופציונלי מגדירים את הערך true כדי לאכוף את המדיניות, או את הערך false כדי להשבית את המדיניות. המדיניות לא נאכפת גם אם היא עדיין משויכת לזרימה.
async   FALSE הוצא משימוש המאפיין הזה הוצא משימוש.

בטבלה הבאה מתוארים רכיבי המשנה של <ExternalCallout>.

רכיב צאצא חובה תיאור
<TimeoutMs> חובה הזמן הקצוב לתפוגה של בקשות gRPC באלפיות השנייה.
<GrpcConnection> חובה מציינת את השם של TargetServer קיים שיהיה שרת ה-gRPC שאליו יישלחו בקשות.
<Configurations> אופציונלי המדיניות הזו מאפשרת להגדיר היבטים שונים של המדיניות ExternalCallout, כולל הרכיבים <Property> ו-<FlowVariable>.

דוגמה 1

דוגמאות פעילות של ExternalCallout זמינות בExternal Callout Samples ב-GitHub.

בדוגמה הבאה מוצגת הגדרה של מדיניות ExternalCallout.

<ExternalCallout enabled="true" continueOnError="false" name="ExternalCallout-1">
  <DisplayName>External Callout 1</DisplayName>
  <TimeoutMs>5000</TimeoutMs>
  <GrpcConnection>
    <Server name="external-target-server"/>
  </GrpcConnection>
  <Configurations>
    <Property name="with.request.content">true</Property>
    <Property name="with.request.headers">false</Property>
    <Property name="with.response.content">true</Property>
    <Property name="with.response.headers">false</Property>
    <FlowVariable>example1.flow.variable</FlowVariable>
    <FlowVariable>example2.flow.variable</FlowVariable>
  </Configurations>
<ExternalCallout>

בדוגמה הזו נשלחת בקשה לשרת gRPC חיצוני שמיוצג על ידי TargetServer בשם external-target-server, עם ההגדרות הבאות:

  • <Property>: כולל תוכן של בקשות ותגובות, אבל לא כותרות של בקשות ותגובות, בבקשה שנשלחת לשרת gRPC.
  • <FlowVariable>: כולל משתני Flow נוספים example1.flow.variable ו-example2.flow.variable, שצוינו על ידי רכיבי FlowVariable, בבקשה שנשלחה לשרת gRPC.

דוגמה 2

בדוגמה הבאה, המאפיין useTargetUrl של הרכיב Audience מוגדר ל-true. אם הערך של useTargetUrl הוא true, שם המארח של שרת היעד של gRPC משמש כקהל. לדוגמה, אם המארח של השרת הוא my-grpc-server-java.a.run.app, קהל היעד שייעשה בו שימוש יהיה https://my-grpc-server-java.a.run.app.

<ExternalCallout continueOnError="false" enabled="true" name="External-Callout-1">
  <DisplayName>External-Callout-1</DisplayName>
  <GrpcConnection>
    <Server name="cloud_run_server_name"/>
    <Authentication>
      <GoogleIDToken>
        <Audience useTargetUrl="true"/>
      </GoogleIDToken>
    </Authentication>
  </GrpcConnection>
  <TimeoutMs>5000</TimeoutMs>
  <Configurations>
    <Property name="with.request.content">true</Property>
    <Property name="with.request.headers">true</Property>
    <Property name="with.response.content">true</Property>
    <Property name="with.response.headers">true</Property>
    <FlowVariable>example.flow.variable</FlowVariable>
    <FlowVariable>another.flow.variable</FlowVariable>
  </Configurations>
</ExternalCallout>

הפניה לרכיב צאצא

בקטעים הבאים מתוארים רכיבי הבן של ExternalCallout.

<TimeoutMs>

הזמן הקצוב לתפוגת הבקשה באלפיות השנייה לבקשות gRPC. הערך <TimeoutMs> חייב להיות מספר חיובי.

<GrpcConnection>

רכיב <GrpcConnection> מגדיר את שרת ה-gRPC כ-TargetServer קיים, שמוגדר על ידי המאפיין name. אפשר לעיין בדף העזר של המשאב TargetServer.

הערה: הפרוטוקול TargetServer צריך להיות GRPC.

לדוגמה, הקוד הבא

<GrpcConnection>
  <Server name="external-target-server"/>
</GrpcConnection>

מציין ששרת ה-gRPC הוא TargetServer קיים בשם external-target-server.

משתמשים ברכיב <Authentication> (שמתואר בהמשך הקטע הזה) כדי ליצור אסימון OpenID Connect שהונפק על ידי Google, כדי לבצע קריאות מאומתות לשירותים מבוססי gRPC, כמו שירותים בהתאמה אישית שמתארחים ב-Cloud Run.

בטבלה הבאה מתוארים רכיבי המשנה של <GrpcConnection>.

רכיב צאצא חובה? תיאור
רכיב <Server> חובה מציינים את שרת ה-gRPC.
רכיב <Authentication> אופציונלי יצירת אסימון OpenID Connect שהונפק על ידי Google כדי לבצע קריאות מאומתות לשירותים מבוססי gRPC, כמו Cloud Run.

רכיב <Server>

מציינים את שרת ה-gRPC.

בטבלה הבאה מתוארים המאפיינים של רכיב <Server>.

מאפיין תיאור ברירת מחדל נוכחות סוג
name

השם של TargetServer קיים שיהיה שרת gRPC לשליחת בקשות אליו.

לא רלוונטי חובה String

רכיב <Authentication>

יצירת אסימון OpenID Connect שהונפק על ידי Google כדי לבצע קריאות מאומתות לשירותים מבוססי gRPC, כמו שירותים בהתאמה אישית שמתארחים ב-Cloud Run. כדי להשתמש ברכיב הזה, צריך לבצע את שלבי ההגדרה והפריסה שמתוארים במאמר בנושא שימוש באימות של Google. אם המדיניות מוגדרת בצורה נכונה, היא יוצרת טוקן אימות ומוסיפה אותו לבקשת השירות.

לרכיב הזה יש רכיב צאצא אחד שנדרש: GoogleIDToken.

ברירת מחדל לא רלוונטי
חובה? זה שינוי אופציונלי.
סוג סוג מורכב
רכיב אב <GrpcConnection>
רכיבי צאצא <GoogleIDToken>

רכיב Authentication משתמש בתחביר הבא:

תחביר

<ExternalCallout>
...
  <GrpcConnection>
    <Server name="cloud_run_server_name"/>
    <Authentication>
      <HeaderName ref="FLOW_VARIABLE">STRING</HeaderName>
      <GoogleIDToken>
         <Audience ref="variable-1">STRING</Audience>
         <IncludeEmail ref="variable-2">BOOLEAN</IncludeEmail>
      </GoogleIDToken>
    </Authentication>
  </GrpcConnection>
</ExternalCallout>

דוגמה

בדוגמה הבאה מוצג הרכיב GoogleIDToken:

<ExternalCallout continueOnError="false" enabled="true" name="External-Callout-1">
  <DisplayName>External-Callout-1</DisplayName>
  <GrpcConnection>
     <Server name="cloud_run_server_name"/>
     <Authentication>
        <HeaderName ref='my-variable'>X-Serverless-Authorization</HeaderName>
        <GoogleIDToken>
           <Audience>https://cloudrun-hostname.a.run.app</Audience>
        </GoogleIDToken>
     </Authentication>
  </GrpcConnection>
  <TimeoutMs>5000</TimeoutMs>
  <Configurations>
    <Property name="with.request.content">true</Property>
    <Property name="with.request.headers">true</Property>
    <Property name="with.response.content">true</Property>
    <Property name="with.response.headers">true</Property>
    <FlowVariable>example.flow.variable</FlowVariable>
    <FlowVariable>another.flow.variable</FlowVariable>
  </Configurations>
</ExternalCallout>
מאפיינים

אין.

רכיב צאצא <HeaderName>

כברירת מחדל, כשקיימת הגדרת אימות, Apigee יוצר אסימון bearer ומזריק אותו לכותרת Authorization בהודעה שנשלחת למערכת היעד. רכיב HeaderName מאפשר לציין את השם של כותרת אחרת שתכיל את אסימון ה-Bearer. התכונה הזו שימושית במיוחד כשמטרת הבקשה היא שירות Cloud Run שמשתמש בכותרת X-Serverless-Authorization. הכותרת Authorization, אם היא קיימת, לא משתנה ונשלחת גם היא בבקשה.

ברירת מחדל לא רלוונטי
חובה? לא
סוג String
רכיב אב <Authentication>
רכיבי צאצא ללא

רכיב HeaderName משתמש בתחביר הבא:

תחביר

<ExternalCallout>
...
  <Authentication>
    <HeaderName ref="FLOW_VARIABLE">STRING</HeaderName>
    <GoogleIDToken>
    ...
    </GoogleIDToken>
  </Authentication>
  ...
</ExternalCallout>

עם מחרוזת סטטית

בדוגמה הזו, אסימון ה-bearer שנוצר מתווסף כברירת מחדל לכותרת בשם X-Serverless-Authorization שנשלחת למערכת היעד. הכותרת Authorization, אם היא קיימת, לא משתנה ונשלחת גם היא בבקשה.

<Authentication>
  <HeaderName>X-Serverless-Authorization</HeaderName>
  <GoogleIDToken>
    <Audience>https://cloudrun-hostname.a.run.app</Audience>
  </GoogleIDToken>
</Authentication>

עם הפניה למשתנה

בדוגמה הזו, אסימון ה-Bearer שנוצר נוסף כברירת מחדל לכותרת בשם X-Serverless-Authorization שנשלחת למערכת היעד. אם ל-my-variable יש ערך, המערכת תשתמש בערך הזה במקום במחרוזת ברירת המחדל. הכותרת Authorization, אם היא קיימת, לא משתנה ונשלחת גם היא בבקשה.

<Authentication>
  <HeaderName ref='my-variable'>X-Serverless-Authorization</HeaderName>
  <GoogleIDToken>
    <Audience>https://cloudrun-hostname.a.run.app</Audience>
  </GoogleIDToken>
</Authentication>
רכיב צאצא <GoogleIDToken>

יצירת אסימוני OpenID Connect שהונפקו על ידי Google כדי לבצע קריאות מאומתות לשירותי Google, כמו שירותים בהתאמה אישית שמתארחים ב-Cloud Run.

ברירת מחדל לא רלוונטי
חובה? חובה
סוג String
רכיב אב <Authentication>
רכיבי צאצא <Audience>
<IncludeEmail>

רכיב GoogleIDToken משתמש בתחביר הבא:

תחביר

<ExternalCallout>
...
  <GrpcConnection>
    <Server name="cloud_run_server_name"/>
    <Authentication>
      <GoogleIDToken>
        <Audience ref="context-variable" useTargetUrl='BOOLEAN'>STRING</Audience>
        <IncludeEmail ref="context-variable">BOOLEAN</IncludeEmail>
      </GoogleIDToken>
    </Authentication>
  </GrpcConnection>
</ExternalCallout>

דוגמה

בדוגמה הבאה מוצג הרכיב GoogleIDToken:

<Authentication>
  <GoogleIDToken>
      <Audience>https://httpserver0-bar.run.app</Audience>
      <IncludeEmail>true</IncludeEmail>
  </GoogleIDToken>
</Authentication>
אלמנט צאצא <Audience>

הקהל של אסימון האימות שנוצר, למשל ה-API או החשבון שהאסימון מעניק גישה אליהם.

אם הערך של Audience ריק, ref ריק או שהערך שלו הוא ריק, ו-useTargetUrl הוא true, אז המערכת משתמשת בערך 'https://' + (שם המארח של שרת היעד של gRPC) כקהל. לדוגמה, אם המארח של השרת הוא my-grpc-server-java.a.run.app, הקהל שבו נעשה שימוש יהיה https://my-grpc-server-java.a.run.app.

ערך ברירת המחדל של useTargetUrl הוא false.

<Audience>explicit-audience-value-here</Audience>

or:

<Audience ref='variable-name-here'/>

or:

<Audience ref='variable-name-here' useTargetUrl='true'/>

or:

<Audience useTargetUrl='true'/>
ברירת מחדל לא רלוונטי
חובה? חובה
סוג String
רכיב אב <GoogleIDToken>
רכיבי צאצא אין.
אלמנט צאצא <IncludeEmail>

אם הערך הוא true, אסימון האימות שנוצר יכיל את הטענות email ו-email_verified של חשבון השירות.

ברירת מחדל FALSE
חובה? אופציונלי
סוג בוליאני
רכיב אב <GoogleIDToken>
רכיבי צאצא אין.

<Configurations>

האלמנט <Configurations> מאפשר להגדיר היבטים שונים של המדיניות ExternalCallout, כולל <Property> ו-<FlowVariable>.

בטבלה הבאה מתוארים רכיבי המשנה של <Configurations>.

רכיב צאצא חובה? תיאור
<Property> חובה

ההגדרה קובעת אם כותרות של בקשות/תגובות ו/או תוכן יישלחו לשרת. הערכים האפשריים הם true או false. ברירת המחדל היא false.

<FlowVariable> חובה

מציינים אילו משתני זרימה נוספים צריך לשלוח לשרת.

<Property>

הרכיב <Property> מציין אם כותרות ו/או תוכן של בקשה/תגובה יישלחו לשרת. הערכים האפשריים הם true (הפריט יישלח) או false (הפריט לא יישלח). ערך ברירת המחדל הוא false.

בטבלה הבאה מתוארים המאפיינים של רכיב <Property>.

מאפיין תיאור ברירת מחדל נוכחות סוג
name

מציינת איזה תוכן יישלח לשרת. הערכים האפשריים של name הם:

  • with.request.content
  • with.request.headers
  • with.response.content
  • with.response.headers
לא רלוונטי חובה String

<FlowVariable>

רכיב <FlowVariable> מציין אילו משתני זרימה נוספים יישלחו לשרת. הערך של <FlowVariable> הוא קידומת של משתנה, ולא שם המשתנה המלא. לדוגמה , אם רכיב הוא a.b.c, הערך של משתנה בשם a.b.c יישלח לשרת. באופן דומה, הערך של משתנה בשם a.b.c.my-variable יישלח לשרת. אבל הערך של משתנה בשם a.x.another-variable לא יישלח, כי אין לו את התחילית a.b.c. ריכזנו כאן כמה דוגמאות

<Configurations>
  <FlowVariable>a.b.c</FlowVariable>
  <FlowVariable>d.e.f</FlowVariable>
</Configurations>

הפניה לשגיאה

שגיאות בהטמעה

שם השגיאה מטרה
FAILED_PRECONDITION השגיאה הזו מתרחשת אם חסר חשבון שירות כשהפרוקסי מוגדר עם התג <Authentication>.

לדוגמה:

Deployment of \"organizations/foo/apis/apiproxy/revisions/1\"
requires a service account identity, but one was not provided
with the request.
PERMISSION_DENIED השגיאה הזו מתרחשת אם יש בעיית הרשאה בחשבון השירות, אם ה-proxy מוגדר עם התג <Authentication>. סיבות אפשריות:
  • חשבון השירות לא קיים.
  • חשבון השירות לא נוצר באותו פרויקט בענן של Google כמו הארגון ב-Apigee.
  • לפורס יש הרשאה iam.serviceAccounts.actAs בחשבון השירות. פרטים נוספים זמינים במאמר מידע על הרשאות לחשבון שירות.

שגיאות זמן ריצה

בטבלה הבאה מתוארות שגיאות זמן ריצה, שיכולות להתרחש כשהמדיניות מופעלת.

קוד תקלה סטטוס HTTP מטרה
GrpcTlsInitFailed 500

השגיאה הזו תתרחש אם יש בעיות בהפעלת TLS בשרת gRPC (למשל בעיות ב-Keystore או ב-truststore).

steps.externalcallout.[error_code] 500

הערך של [error_code] נקבע לפי השדה errorCode בהודעת השגיאה. מחרוזת השגיאה תהיה השדה faultstring של הודעת השגיאה.

steps.externalcallout.ExecutionError 500

השגיאה הזו תתרחש אם יתרחש חריג אחר במהלך הביצוע של המדיניות הזו. החריגה הבסיסית תיחשף ב-faultstring. אם הייתה בעיה בפרטי הכניסה לשרת gRPC, השגיאה תיראה כך:

{
  "fault": {
    "faultstring": "Encountered the following exception while sending the gRPC request or
     processing the response: [io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed
     to obtain metadata].",
    "detail": {
      "errorcode": "steps.externalcallout.ExecutionError"
    }
  }
}

אפשר לעיין ביומנים של ה-MP כדי לקבל רמזים נוספים לניפוי באגים.

googletoken.EmptyIDTokenAudience 500

המאפיין <GoogleIDToken> מופעל אבל המאפיין useTargetUrl מוגדר לערך false ולא צוין ערך למאפיין <Audience> ישירות או באמצעות הפניה בזמן השגיאה.

steps.externalcallout.ExecutionError

עם מחרוזת שגיאה:

Encountered the following exception while sending the gRPC request or processing the response: [io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed to obtain metadata]

500

השגיאה הזו מתרחשת אם proxy ל-API מוגדר עם הרכיב <Authentication>. סיבות אפשריות:

  • חשבון השירות שנפרס עם ה-proxy:
    • לא קיים בפרויקט (הוא היה קיים בזמן הפריסה, אבל נמחק אחרי הפריסה)
    • הושבת
    • (רק ב-Apigee hybrid) לא הוקצה התפקיד roles/iam.serviceAccountTokenCreator בחשבון השירות apigee-runtime.
  • (Apigee hybrid בלבד) ממשק IAMCredentials ה-API מושבת בפרויקט המקור של חשבון השירות apigee-runtime.

    הערה: רק ב-Apigee hybrid, כדאי לבדוק את היומן של קונטיינר זמן הריצה ולחפש את המחרוזת externalcallout.ExecutionError כדי למצוא הודעות שגיאה מפורטות יותר שיכולות לעזור בניפוי הבאגים של הבעיה.

steps.externalcallout.ExecutionError עם faultstring שמכיל PERMISSION DENIED.

לדוגמה, מחרוזת השגיאה תיראה כך ב-Cloud Run:

Encountered the following exception while sending the gRPC request or processing the response: [io.grpc.StatusRuntimeException: PERMISSION_DENIED: HTTP status code 403 …]

500

השגיאה הזו מתרחשת אם proxy ל-API מוגדר עם הרכיב <Authentication>. סיבות אפשריות:

  • חשבון השירות של ה-proxy קיים ומופעל, אבל אין לו את ההרשאות הנכונות לגשת לשירות.
  • השירות דורש אימות, אבל בבקשה לא צוינה כותרת אימות (לדוגמה: קובץ ה-XML של האימות לא נכלל בקובץ ה-XML של המדיניות).

שגיאות שונות

בטבלה הבאה מתוארות שגיאות שונות. פרטים נוספים מופיעים בקטע 'הסיבה'.

קוד תקלה מטרה
ReferencesExistToGrpcServer

השגיאה הזו תופיע אם משתמש ינסה למחוק שרת יעד של gRPC, אבל השרת עדיין נמצא בשימוש במדיניות אחרת.

Faults

משתני התקלה בטבלה הבאה מוגדרים כברירת מחדל לכל כללי המדיניות. ראו משתנים שספציפיים לשגיאות במדיניות.

משתנים כאשר: דוגמאות
fault.name="fault_name" fault_name הוא שם התקלה, כפי שמופיע בטבלה של שגיאות זמן הריצה שלמעלה. שם התקלה הוא החלק האחרון של קוד התקלה. fault.name matches "ExecutionError".
externalcallout.[policy_name].failed policy_name הוא השם שהמשתמש הגדיר למדיניות שגרמה לשגיאה. externalcallout.ExternalCallout-1.failed = true

נושאים קשורים