ExternalCallout policy

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

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

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

המדיניות ExternalCallout מאפשרת לשלוח בקשות gRPC 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 תואם ל-ExecutionError.
externalcallout.[policy_name].failed ‫policy_name הוא השם שהמשתמש הגדיר למדיניות שגרמה לשגיאה. externalcallout.ExternalCallout-1.failed = true

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