شرایط با متغیرهای جریان

درحال مشاهده اسناد Apigee Edge هستید.
به اسناد Apigee X بروید.
اطلاعات

عبارت‌های شرطی ساختار کنترلی رایجی در همه زبان‌های برنامه‌نویسی هستند. مانند زبان برنامه‌نویسی، پیکربندی پراکسی API از گزاره‌های شرطی برای «جریان‌ها»، «خط‌مشی‌ها»، «مراحل»، و «قوانین مسیر» پشتیبانی می‌کند. با تعریف کردن گزاره‌های شرطی، رفتار پویا را برای میانای برنامه‌سازی کاربردی خود تعریف می‌کنید. این رفتار پویا به شما امکان می‌دهد کارهایی مثل تبدیل XML به JSON را فقط برای دستگاه‌های همراه انجام دهید، یا براساس نوع محتوا یا فعل HTTP پیام درخواست، به نشانی وب زیرینه هدایت کنید.

این موضوع نشان می‌دهد که چگونه از شرایط برای اعمال پویا ویژگی‌های مدیریت API در زمان اجرا بدون نوشتن کد استفاده کنید.

پیکربندی گزاره‌های شرطی

عملکرد شرطی در پراکسی‌های API بااستفاده از ترکیبی از شرایط و متغیرها پیاده‌سازی می‌شود. گزاره شرطی بااستفاده از عنصر «شرط» ایجاد می‌شود. شرط زیر خالی است:

<Condition></Condition>

برای ایجاد یک عبارت شرطی، یک عملگر شرطی و یک متغیر اضافه می‌کنید تا ساختار زیر را ایجاد کنید:

<Condition>{variable.name}{operator}{"value"}</Condition>

اپراتورهای شرطی پشتیبانی‌شده شامل = (مساوی)، != (نامساوی)، و > (بزرگ‌تر از) می‌شود. برای خوانایی، می‌توانید شرط‌ها را به‌صورت نوشتار: equals، notequals، greaterthan نیز بنویسید.

هنگام کار با مسیرهای نشانی وب می‌توانید از ~/ یا MatchesPath استفاده کنید. همچنین می‌توانید عبارت‌های باقاعده JavaRegex را با عامل ~~ مطابقت دهید.

از شرایط برای تعریف جریان‌های شرطی پراکسی API برای منابع API زیرینه استفاده می‌شود، که در ایجاد جریان‌های شرطی برای منابع API زیرینه توضیح داده شده است. برای فهرست کامل شرط‌ها، به مرجع شرط‌ها مراجعه کنید.

متغیر

شرایط با ارزیابی مقادیر متغیرها کار خود را انجام می‌دهند. متغیر ویژگی تراکنش HTTP است که توسط پراکسی API اجرا می‌شود، یا ویژگی پیکربندی پراکسی API است. هرگاه یک پراکسی API درخواستی از یک برنامه دریافت می‌کند، Apigee Edge فهرست بلندی از متغیرها را که با مواردی مثل زمان سیستم، اطلاعات شبکه برنامه، سرایندهای HTTP در پیام‌ها، پیکربندی پراکسی API، اجرای خط‌مشی، و غیره مرتبط هستند تکمیل می‌کند. این کار بافت غنی‌ای ایجاد می‌کند که می‌توانید از آن برای تنظیم گزاره‌های شرطی استفاده کنید.

متغیرها همیشه از نماد نقطه‌دار استفاده می‌کنند. برای مثال، سرایندهای HTTP در پیام درخواست به‌عنوان متغیرهایی به‌نام request.header.{header_name} دردسترس هستند. بنابراین برای ارزیابی سرصفحه Content-type، می‌توانید از متغیر request.header.Content-type استفاده کنید. برای مثال، request.header.Content-type = "application/json" نشان می‌دهد که نوع محتوای درخواست باید JSON باشد.

تصور کنید که باید عبارت شرطی‌ای بسازید که باعث شود خط‌مشی فقط زمانی اجرا شود که پیام درخواست GET باشد. برای ایجاد شرطی که فعل HTTP درخواست را ارزیابی می‌کند، بیانیه شرطی زیر را ایجاد می‌کنید. متغیر در این شرط request.verb است. مقدار متغیر GET است. اپراتور = است.

<Condition>request.verb = "GET"</Condition>
همچنین می‌توانید از این موارد استفاده کنید:
<Condition>request.verb equals "GET"</Condition>

‫Edge از چنین عبارتی برای ارزیابی شرایط استفاده می‌کند. اگر فعل HTTP مرتبط با درخواست GET باشد، مثال بالا به درست ارزیابی می‌شود. اگر فعل HTTP مرتبط با درخواست POST باشد، عبارت به false ارزیابی می‌شود.

برای فعال کردن رفتار پویا، می‌توانید «شرایط» را به «جریان‌ها»، «مراحل»، و «قوانین مسیر» پیوست کنید.

وقتی شرطی را به «جریان» پیوست می‌کنید، «جریان شرطی» ایجاد می‌کنید. جریان‌های شرطی فقط زمانی اجرا می‌شوند که شرط به درست ارزیابی شود. می‌توانید هر تعداد «خط‌مشی» را که می‌خواهید به «جریان» شرطی پیوست کنید. «جریان» شرطی به شما امکان می‌دهد قوانین پردازش بسیار تخصصی برای پیام‌های درخواست یا پاسخ که معیارهای خاصی را برآورده می‌کنند بسازید.

برای مثال، برای ایجاد یک «جریان» که فقط وقتی فعل درخواست GET است اجرا می‌شود:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
</Flows>

برای ایجاد یک جریان برای GET و دیگری برای POST:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
  <Flow name="ExecuteForPOSTs">
  <Condition>request.verb="POST"</Condition>
  </Flow>
</Flows>

همان‌طور که در مثال زیر نشان داده شده است، می‌توانید این شرط را به خود «مرحله خط‌مشی» اعمال کنید. «شرط» زیر باعث می‌شود «خط‌مشی VerifyApiKey» فقط درصورتی اجرا شود که پیام درخواست از نوع «پست» باشد.

<PreFlow name="PreFlow">
    <Request>
        <Step>
            <Condition>request.verb equals "POST"</Condition>
            <Name>VerifyApiKey</Name>
        </Step>
    </Request>
</PreFlow>

پس‌از تعریف چنین «جریان‌های» شرطی، می‌توانید «خط‌مشی‌ها» را به آن‌ها پیوست کنید و با این کار، کارگزار میانای برنامه‌سازی کاربردی را قادر سازید یک مجموعه خط‌مشی را برای درخواست‌های GET و مجموعه خط‌مشی دیگری را برای درخواست‌های POST اعمال کند.

برای اطلاعات مرجع جامع، منابع زیر را ببینید:

مثال ۱

نمونه زیر یک جریان شرطی واحد به‌نام Convert-for-devices را نشان می‌دهد که در جریان پاسخ ProxyEndpoint پیکربندی شده است. «شرط» را به‌عنوان عنصری به نهادی که شرط برای آن اعمال می‌شود اضافه کنید. در این مثال، شرط یکی از عناصر جاری‌سازی است. بنابراین، هرگاه عبارت به درست ارزیابی شود، جریان اجرا خواهد شد.

<Flows>
  <Flow name="Convert-for-devices">
  <Condition>(request.header.User-Agent = "Mozilla")</Condition>
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

برای هر درخواستی که از برنامه دریافت می‌شود، Edge مقادیر همه سرایندهای HTTP موجود را به‌عنوان متغیر ذخیره می‌کند. اگر درخواست حاوی سرایند HTTP به‌نام User-Agent باشد، آن سرایند و مقدارش به‌عنوان متغیری به‌نام request.header.User-Agent ذخیره می‌شود.

با درنظر گرفتن پیکربندی ProxyEndpoint در بالا، Edge مقدار متغیر request.header.User-Agent را بررسی می‌کند تا ببیند آیا شرط به درست ارزیابی می‌شود یا نه.

اگر شرط به درست ارزیابی شود، یعنی مقدار متغیر request.header.User-Agent برابر با Mozilla باشد، «جریان» شرطی اجرا می‌شود و خط‌مشی XMLtoJSON به‌نام ConvertToJSON اعمال می‌شود. درغیراین‌صورت، «جریان» اجرا نمی‌شود و پاسخ XML بدون تغییر (در قالب XML) به برنامه درخواست‌کننده برگردانده می‌شود.

مثال ۲

بیایید از مثال خاصی استفاده کنیم که در آن باید پیام پاسخ را از XML به JSON تبدیل کنید—اما فقط برای دستگاه‌های همراه. ابتدا خط‌مشی‌ای بسازید که پاسخ با قالب XML را از «میانای برنامه‌سازی کاربردی آب‌وهوا» به JSON تبدیل کند:

<XMLToJSON name="ConvertToJSON">
  <Options>
  </Options>
  <OutputVariable>response</OutputVariable>
  <Source>response</Source>
</XMLToJSON>

پیکربندی خط‌مشی بالا به پراکسی میانای برنامه‌سازی کاربردی می‌گوید پیام پاسخ را بگیرد، تبدیل از XML به JSON را با تنظیمات پیش‌فرض انجام دهد، و سپس نتیجه را در پیام پاسخ جدید بنویسد. (اگر پیام درخواست را از XML به JSON تبدیل می‌کنید، کافی است هر دو مقدار را روی request تنظیم کنید.)

مراجعه کنید

ازآنجایی‌که می‌خواهید پاسخ‌ها را از XML به JSON تبدیل کنید، باید «جریان» پاسخ شرطی را برای انجام تبدیل پیکربندی کنید. برای مثال، برای تبدیل همه پاسخ‌ها از XML به JSON قبل‌از اینکه به برنامه مشتری برگردانده شوند، «جریان» پاسخ ProxyEndpoint زیر را پیکربندی کنید.

<Flows>
  <Flow name="Convert-for-devices">
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

وقتی بااستفاده از درخواست استاندارد، API را فراخوانی می‌کنید، پاسخ در قالب JSON قالب‌بندی می‌شود.

بااین‌حال، هدف شما این است که گزارش‌های «آب‌وهوا» را فقط وقتی مشتری درخواست‌کننده دستگاه همراه است به JSON تبدیل کنید. برای فعال کردن چنین رفتار پویایی، باید عبارت شرطی به «جریان» اضافه کنید.

جریان مشروط را امتحان کنید

در این درخواست نمونه، سرایند HTTP User-Agent روی Mozilla تنظیم شده است و باعث می‌شود عبارت شرطی به درست ارزیابی شود و جریان شرطی Convert-for-devices اجرا شود.

$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282

یا برای چاپ زیبا در جایی که Python دردسترس است:

$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282 | python -mjson.tool

پاسخ نمونه:

. . .

"yweather_forecast": [
         {
              "code": "11",
              "date": "12 Dec 2012",
              "day": "Wed",
              "high": "55",
              "low": "36",
              "text": "Showers"
          },
          {
              "code": "32",
              "date": "13 Dec 2012",
              "day": "Thu",
              "high": "56",
              "low": "38",
              "text": "Sunny"
          }
      ]
  }

. . .

درخواستی که بدون سرایند User-Agent ارسال شود، یا مقدار آن متفاوت از Mozilla باشد، منجر به پاسخ با قالب XML خواهد شد.

$ curl http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282

پاسخ XML بدون تغییر برگردانده می‌شود.

پاسخ نمونه:

<yweather:forecast day="Wed" date="12 Dec 2012" low="36" high="55" text="Showers" code="11" /> <yweather:forecast day="Thu" date="13 Dec 2012" low="38" high="56" text="Sunny" code="32" />

تطبیق الگو

این بخش نحوه استفاده از تطبیق الگو با شرایط در جریان Apigee را شرح می‌دهد.

اپراتورها

این بخش نحوه استفاده از عملگرهای تطبیق الگو زیر را در گزاره‌های شرطی توضیح می‌دهد:

موارد منطبق

ابتدا بیایید به عملگر شرطی «مطابقت‌ها» یا «~» نگاه کنیم. این دو عملگر یکسان هستند -- نسخه انگلیسی، «Matches»، به‌عنوان گزینه خواناتری درنظر گرفته می‌شود.

خلاصه: عامل «تطابق‌ها» دو امکان به شما می‌دهد. یا رشته را دقیقاً مطابقت دهید یا با «*» مطابقت نویسه عام انجام دهید. همان‌طور که انتظار دارید، نویسه عام با صفر یا چند نویسه مطابقت می‌کند. بگذارید ببینیم این چگونه کار می‌کند.

استفاده کنید.

‫XML زیر وضعیت «مرحله» را نشان می‌دهد. وقتی شرط به درست ارزیابی شود، خط‌مشی SomePolicy را اجرا می‌کند. در این مثال، متغیر proxy.pathsuffix را آزمایش می‌کنیم، متغیری درونی در Edge که پسوند مسیر درخواست را ذخیره می‌کند. بااین‌حال، توجه داشته باشید که می‌توانید مقدار هر متغیر جاری‌سازی را که حاوی رشته است آزمایش کنید. بنابراین، در این مورد، اگر مسیر پایه درخواست ورودی /animals باشد و درخواست /animals/cat باشد، پسوند مسیر رشته تحت‌اللفظی «/cat» است.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix Matches "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

پرسش: کدام پسوند مسیر پراکسی باعث می‌شود SomePolicy اجرا شود؟ فقط یک امکان وجود دارد.

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا پسوند مسیر پراکسی دقیقاً با «/cat» مطابقت دارد. اگر پسوند /bat یا /dog یا «/» یا چیز دیگری باشد اجرا نخواهد شد.

اکنون این عبارت شرطی را که در آن از نویسه عام «*» استفاده می‌کنیم درنظر بگیرید:

<Condition>(proxy.pathsuffix Matches "/*at")</Condition>

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا نویسه عام با هر نویسه‌ای مطابقت دارد، و "/cat« مطابقت دارد.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/bat

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا نویسه عام با هر نویسه‌ای مطابقت دارد، "/bat" مطابقت دارد.

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/owl

آیا خط‌مشی اجرا می‌شود؟ قطعاً نه -- اگرچه نویسه عام با «o» مطابقت دارد، حروف «wl» مطابقت ندارد.

اکنون، بیایید نویسه عام را به انتهای پسوند منتقل کنیم:

<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا نویسه عام با صفر یا بیشتر از هر نویسه‌ای مطابقت دارد.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/bat

آیا خط‌مشی اجرا می‌شود؟ نه، «/bat» مطابقت ندارد.

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat123

آیا خط‌مشی اجرا می‌شود؟ بله، نویسه عام با صفر یا بیشتر از هر نویسه‌ای مطابقت می‌کند، بنابراین «123» مطابقت ایجاد می‌کند.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat/bird/mouse

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا نویسه عام با صفر یا بیشتر از هر نویسه‌ای مطابقت دارد، بنابراین «/bird/mouse» مطابقت ایجاد می‌کند. توجه کنید که چگونه عبارتی مانند این می‌تواند شما را به دردسر بیندازد زیرا با هر چیزی پس‌از نویسه‌های تحت‌اللفظی مطابقت دارد!

پرسش: آیا عامل «مطابقت‌ها» حروف‌حساس است؟

بله. فرض کنید شرایطی مانند این دارید:

<Condition>(proxy.pathsuffix Matches "/*At")</Condition>

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ نه، نویسه عام با هر حرفی (بدون درنظر گرفتن حروف بزرگ و کوچک) مطابقت دارد، اما حرف کوچک «a» با «A» مطابقت ندارد.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/bAt

آیا خط‌مشی اجرا می‌شود؟ بله، حروف منطبق است.

پرسش: چگونه نویسه‌ها را با عامل «مطابقت‌ها» فرار کنم؟

برای فرار از نویسه‌های رزروشده، از نویسه درصد «%» استفاده کنید. برای مثال:

<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ نه، عامل «مطابقت‌ها» به‌دنبال رشته تحت‌اللفظی «c*at» است.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/c*at

پرسش:آیا خط‌مشی اجرا می‌شود؟

بله، این مسیر، اگرچه کمی غیرمعمول است، مطابقت دارد.

JavaRegex

همان‌طور که می‌بینید، عامل «مطابقت‌ها» برای موقعیت‌های ساده عالی است. اما می‌توانید از اپراتور دیگری، اپراتور «JavaRegex» یا «~~» استفاده کنید. این دو اپراتور یکسان هستند، با این تفاوت که JavaRegex خواناتر درنظر گرفته می‌شود. این ویژگی JavaRegex نامیده می‌شود زیرا امکان تطبیق الگوی عبارت باقاعده را فراهم می‌کند و Edge از همان قوانین کلاس‌های بسته java.util.regex در زبان Java پیروی می‌کند. نحوه عملکرد اپراتور JavaRegex با اپراتور Matches بسیار متفاوت است، بنابراین مهم است که این دو را با هم اشتباه نگیرید!

خلاصه: عامل «JavaRegex» به شما امکان می‌دهد از نحو عبارت باقاعده در گزاره‌های شرطی استفاده کنید.

کد زیر وضعیت «مرحله» را نشان می‌دهد. اگر شرط به درست ارزیابی شود، خط‌مشی SomePolicy را اجرا می‌کند. در این مثال، متغیر proxy.pathsuffix را آزمایش می‌کنیم، متغیری درونی در Edge که پسوند مسیر درخواست را ذخیره می‌کند. اگر مسیر پایه درخواست ورودی /animals باشد و درخواست /animals/cat باشد، پسوند مسیر رشته تحت‌اللفظی «/cat» است.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix JavaRegex "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

پرسش: کدام پسوند مسیر پراکسی باعث می‌شود SomePolicy اجرا شود؟ درست مثل با عامل «مطابقت‌ها»، در این مورد فقط یک امکان وجود دارد.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا پسوند مسیر پراکسی دقیقاً با «/cat» مطابقت دارد. اگر پسوند /bat یا /dog یا هر چیز دیگری باشد، اجرا نخواهد شد.

اکنون، بیایید بااستفاده از کمیت‌گر «*» عبارت باقاعده ایجاد کنیم. این کمیت‌سنج با صفر یا بیشتر از نویسه قبلی مطابقت دارد.

<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ نه! کمیت‌گر «*» با صفر یا بیشتر از نویسه پیشین، که «c» است، مطابقت دارد.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/ccccct

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا نویسه عام با صفر یا چند نویسه قبلی مطابقت دارد.

سپس، از کمیت‌گر «?» استفاده می‌کنیم که نویسه قبلی را یک بار یا اصلاً مطابقت می‌دهد.

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ بله. کمیت‌گر «?» با صفر یا یک رخداد از نویسه پیشین، که «a» است، مطابقت دارد.

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/ct

آیا خط‌مشی اجرا می‌شود؟ بله. کمیت‌گر «?» با یک یا هیچ‌کدام از نویسه‌های قبلی مطابقت دارد. در این مورد، هیچ نویسه «a» وجود ندارد، بنابراین شرط به درست ارزیابی می‌شود.

تماس با میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/caat

آیا خط‌مشی اجرا می‌شود؟ نه. کمیت‌گر «؟» با یکی از نویسه‌های قبلی که «a» است مطابقت دارد.

سپس، از سبک «[abc]» یا «گروه‌بندی» عبارت باقاعده استفاده می‌کنیم. با نویسه‌های «a» یا «b» یا «c» مطابقت دارد.

<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ بله. در اینجا از عبارت‌های باقاعده استفاده می‌کنیم و عبارت «[cbr]» با «c»، «b»، یا «r» مطابقت دارد. این تماس‌ها نیز مطابقت دارند:

GET http://artomatic-test.apigee.net/matchtest/bat

GET http://artomatic-test.apigee.net/matchtest/rat

اما این مورد مطابقت ندارد:

GET http://artomatic-test.apigee.net/matchtest/mat

پرسش: آیا عملگر JavaRegex حروف‌حساس است؟

بله. فرض کنید شرایطی مانند این دارید:

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat

آیا خط‌مشی اجرا می‌شود؟ بله، عبارت باقاعده با صفر یا یک نویسه قبلی، که «a» است، مطابقت دارد.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cAt

پرسش: آیا خط‌مشی اجرا می‌شود؟

نه، زیرا «A» بزرگ با «a» کوچک مطابقت ندارد.

MatchesPath

اپراتور MatchesPath را می‌توان به این صورت «~/» نیز مشخص کرد. این اپراتور کمی شبیه اپراتورهای Matches (~) و JavaRegex (~~) است. اما MatchesPath کاملاً متفاوت است.

فقط به‌یاد داشته باشید که این عامل به مسیر به‌عنوان مجموعه‌ای از بخش‌ها نگاه می‌کند. بنابراین، اگر مسیر این باشد: /animals/cats/wild، می‌توانید مسیر را متشکل از بخش‌های «/animals»، «/cats»، و «/wild» درنظر بگیرید.

عملگر MatchesPath به شما امکان می‌دهد از دو نماد نویسه عام استفاده کنید: یک ستاره (*) و دو ستاره (**). ستاره تکی با یک عنصر مسیر مطابقت دارد. علامت ستاره دوتایی با یک یا چند عنصر مسیر مطابقت دارد.

بیایید به یک مثال نگاه کنیم. در این مثال، متغیر proxy.pathsuffix را آزمایش می‌کنیم، متغیری داخلی در Edge که پسوند مسیر درخواست را ذخیره می‌کند. بااین‌حال، توجه داشته باشید که می‌توانید مقدار هر متغیر جریانی را که حاوی رشته است آزمایش کنید.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

پرسش: کدام پسوند مسیر پراکسی باعث می‌شود SomePolicy اجرا شود؟

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/animals

پرسش: آیا خط‌مشی اجرا می‌شود؟

نه، زیرا وضعیت به عنصر مسیر دیگری پس‌از «/animals» نیاز دارد، همان‌طور که «/*» مشخص کرده است.

تماس با میانای برنامه‌سازی کاربردی:

‫GET http://artomatic-test.apigee.net/matchtest/animals/

آیا خط‌مشی اجرا می‌شود؟ بله، مسیر عنصر مسیر دیگری دارد (بخش بعداز «/animals/»)، اما خالی است.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

آیا خط‌مشی اجرا می‌شود؟ بله، زیرا مسیر به‌وضوح عنصری («/cats») دارد که بعداز «/animals» می‌آید

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild

پرسش: آیا خط‌مشی اجرا می‌شود؟

نه، زیرا تک‌ستاره فقط با یک عنصر مسیر مطابقت دارد و این «میانای برنامه‌سازی کاربردی» پس‌از «/animals» بیش‌از یک عنصر دارد.

اکنون بیایید از دو ستاره استفاده کنیم:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

پرسش: کدام پسوند مسیر پراکسی باعث می‌شود SomePolicy اجرا شود؟

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/animals

آیا خط‌مشی اجرا می‌شود؟ نه، زیرا شرط حداقل به یک عنصر مسیر زیر نیاز دارد که توسط «/**» مشخص شده است.

فراخوانی میانای برنامه‌سازی کاربردی:

‫GET http://artomatic-test.apigee.net/matchtest/animals/

آیا خط‌مشی اجرا می‌شود؟

بله، مسیر عنصر مسیر دیگری دارد (بخش بعداز «/animals/»)، اما خالی است.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

آیا خط‌مشی اجرا می‌شود؟

بله، زیرا مسیر حداقل یک عنصری دارد که بعداز «/animals» می‌آید

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild

آیا خط‌مشی اجرا می‌شود؟

بله، زیرا مسیر بیش‌از یک عنصر دارد که پس‌از «/animals» می‌آید

ترکیب کردن ستاره‌ها

می‌توانید از ترکیب‌های ستاره تکی (*) و ستاره دوتایی (**) برای پالایش بیشتر مطابقت مسیر استفاده کنید.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*/wild/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

فراخوانی میانای برنامه‌سازی کاربردی:

همه این فراخوانی‌های API مطابقت ایجاد می‌کنند:

‫GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild/

و

GET http://artomatic-test.apigee.net/matchtest/animals/dogs/wild/austrailian

و

GET http://artomatic-test.apigee.net/matchtest/animals/birds/wild/american/finches

منابع میانای برنامه‌سازی کاربردی

سرویس‌های RESTful مجموعه‌ای از منابع API هستند. منبع API بخشی از مسیر URI است که نهادی را که توسعه‌دهندگان می‌توانند با فراخوانی API شما به آن دسترسی پیدا کنند شناسایی می‌کند. برای مثال، اگر سرویس شما گزارش‌های آب‌وهوا و پیش‌بینی‌های آب‌وهوا ارائه می‌دهد، سرویس زیرینه شما ممکن است دو منبع «میانای برنامه کاربردی» را تعریف کند:

  • http://mygreatweatherforecast.com/reports
  • http://mygreatweatherforecast.com/forecasts

وقتی یک پراکسی API ایجاد می‌کنید (همان‌طور که در ساختن اولین پراکسی API نشان داده شده است)، حداقل یک نشانی وب پایه مستعار ایجاد می‌کنید که به سرویس زیرینه شما نگاشت می‌شود. برای مثال:

نشانی وب پایه زیرینه نشانی وب پراکسی API جدید/معادل
http://mygreatweatherforecast.com http://{your_org}-{environment}.apigee.net/mygreatweatherforecast

در این مرحله می‌توانید بااستفاده از هریک از نشانی‌های وب پایه، تماس‌های «میانای برنامه‌سازی کاربردی» را با زیرینه خود برقرار کنید. اما وقتی از نشانی وب پراکسی API استفاده می‌کنید، اوضاع جالب می‌شود.

علاوه‌بر تحلیل داده‌های API که Edge هنگام استفاده از پراکسی API شروع به جمع‌آوری می‌کند، پراکسی‌ها به شما امکان می‌دهند جریان‌های شرطی را تعریف کنید که به منابع در زیرینه شما نگاشت می‌شوند. درواقع، «اگر تماس GET به منبع /reports وارد شد، Edge باید کاری انجام دهد.»

تصویر زیر تفاوت رفتار بین دو نشانی وب را نشان می‌دهد که درنهایت به زیرینه یکسانی دسترسی دارند. یکی نشانی وب منبع بدون پراکسی است، دیگری پراکسی Edge API با جریان شرطی به همان منبع زیرینه است. در زیر، جریان‌های مشروط را با جزئیات بیشتری توضیح خواهیم داد.

نحوه نگاشت کارگزاران API به منابع زیرینه خاص

با نشانی وب پراکسی API که به نشانی وب پایه سرویس زیرینه نگاشت شده است (وقتی پراکسی را ایجاد می‌کنید)، می‌توانید جاری‌سازی‌های شرطی را به منابع خاصی اضافه کنید، مثل منابع /reports و /forecasts که قبلاً ذکر شد.

فرض کنیم می‌خواهید وقتی تماس به منابع /reports یا /forecasts وارد می‌شود، Edge «کاری انجام دهد». در این مرحله به Edge نمی‌گویید چه کاری انجام دهد، فقط به آن می‌گویید که باید به تماس‌های این منابع گوش دهد. این کار را با شرایط انجام می‌دهید. در پراکسی Edge API، می‌توانید برای /reports و /forecasts جاری‌سازی‌های شرطی ایجاد کنید. برای اهداف مفهومی، XML پراکسی API زیر نشان می‌دهد که این شرایط چگونه ممکن است به‌نظر برسند.

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
    </Flow>
    <Flow name="forecasts">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/forecasts") and (request.verb = "GET")</Condition>
    </Flow>
</Flows>

این شرایط می‌گوید: «وقتی درخواست GET با /reports و /forecasts در نشانی وب می‌آید، Edge هر کاری را که شما (توسعه‌دهنده API) به آن می‌گویید انجام می‌دهد، ازطریق خط‌مشی‌هایی که به آن جریان‌ها پیوست می‌کنید.

اکنون در اینجا نمونه‌ای از نحوه گفتن به Edge برای انجام کاری درصورت برآورده شدن شرایط آورده شده است. در میانای برنامه‌سازی کاربردی زیر پروکسی XML، وقتی درخواست GET به https://yourorg-test.apigee.net/mygreatweatherforecast/reports ارسال می‌شود، Edge خط‌مشی «XML-to-JSON-1» را در پاسخ اجرا می‌کند.

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response>
            <Step>
                <Name>XML-to-JSON-1</Name>
            </Step>
        </Response>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
</Flow>

علاوه‌بر آن جریان‌های شرطی اختیاری، هر پراکسی API با دو جریان پیش‌فرض نیز ارائه می‌شود: <PreFlow> قبل‌از جریان‌های شرطی شما اجرا می‌شود و <PostFlow> بعداز جریان‌های شرطی شما اجرا می‌شود. این موارد برای اجرای خط‌مشی‌ها زمانی که هر تماسی با پراکسی API برقرار می‌شود مفید هستند. برای مثال، اگر می‌خواهید کلید میانای برنامه‌سازی کاربردی برنامه را با هر تماس درستی‌سنجی کنید، صرف‌نظر از اینکه به کدام منبع زیرینه دسترسی پیدا می‌شود، می‌توانید خط‌مشی «درستی‌سنجی کلید میانای برنامه‌سازی کاربردی» را در <PreFlow> قرار دهید. برای اطلاعات بیشتر درباره جریان‌ها، به پیکربندی جریان‌ها مراجعه کنید.

ایجاد جریان‌های شرطی برای منابع زیرینه

تعریف کردن جاری‌سازی‌های شرطی برای منابع زیرینه در پراکسی API کاملاً اختیاری است. بااین‌حال، این جریان‌های شرطی به شما امکان می‌دهند مدیریت و نظارت دقیق را اعمال کنید.

می‌توانید:

  • مدیریت را به‌گونه‌ای اعمال کنید که نشان‌دهنده معناشناسی مدل میانای برنامه‌سازی کاربردی شما باشد
  • اعمال خط‌مشی‌ها و رفتار برنامه‌ریزی‌شده روی مسیرهای منبع (نشانی‌های وب)
  • جمع‌آوری سنجه‌های دقیق برای «سرویس‌های Analytics»

برای مثال، تصور کنید که باید انواع مختلفی از منطق را برای منابع backend /developers به /apps اعمال کنید.

برای انجام این کار، دو جریان شرطی در پراکسی API خود اضافه می‌کنید: /developers و /apps.

در نمای «توسعه» در قاب «پیمایشگر» ویرایشگر پراکسی API، روی نماد + در کنار پیش‌فرض در «نقطه‌های پایان پراکسی» کلیک کنید.

در پنجره «جریان شرطی جدید»، پیکربندی‌های کلیدی زیر را وارد می‌کنید:

  • نام جریان: توسعه‌دهندگان
  • نوع شرط: مسیر
  • مسیر: /developers

اگر تماسی با /developers در انتهای نشانی وب به پراکسی ارسال شود، شرط راه‌اندازی خواهد شد (و خط‌مشی‌ها اجرا خواهند شد).

اکنون یک جاری‌سازی شرطی برای /apps اضافه کنید و فرض کنید می‌خواهید شرط هم در نشانی وب و هم در فعل POST در یک درخواست راه‌اندازی شود. پیکربندی شامل تنظیم موارد زیر است: زیر است:

  • نام جریان: برنامه‌ها
  • نوع شرط: مسیر و فعل
  • مسیر: /apps
  • فعل: POST

اگر تماسی با /apps در انتهای نشانی وب و فعل POST به پراکسی ارسال شود، شرط راه‌اندازی خواهد شد (و خط‌مشی‌ها اجرا خواهند شد).

در قاب «پیمایشگر»، جریان‌های جدیدی برای برنامه‌ها و توسعه‌دهندگان خواهید دید.

یکی از جاری‌سازی‌ها را انتخاب کنید تا پیکربندی جاری‌سازی شرطی را در ویرایشگر پراکسی API نمای کد ببینید:

<Flow name="Apps">
    <Description>Developer apps registered in Developer Services</Description>
    <Request/>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath "/apps") and (request.verb = "POST")</Condition>
</Flow>

همان‌طور که می‌بینید، منابع API به‌سادگی «جریان‌های» شرطی هستند که مسیر نشانی وب درخواست ورودی را ارزیابی می‌کنند. (متغیر proxy.pathsuffix شناسه URI درخواستی را که پس‌از BasePath پیکربندی‌شده در پیکربندی ProxyEndpoint می‌آید شناسایی می‌کند.)

هر منبع «میانای برنامه‌سازی کاربردی» که تعریف می‌کنید توسط یک «جریان» شرطی در پراکسی «میانای برنامه‌سازی کاربردی» پیاده‌سازی می‌شود. (به پیکربندی جریان‌ها مراجعه کنید.)

پس‌از اینکه کارگزار میانای برنامه‌سازی کاربردی را در محیط آزمایش مستقر کردید، درخواست زیر:

http://{org_name}-test.apigee.net/{proxy_path}/apps

باعث می‌شود وضعیت به درست ارزیابی شود و این جریان، همراه با هرگونه خط‌مشی مرتبط، اجرا خواهد شد.

شرط مثال زیر از عبارت باقاعده Java برای تشخیص تماس‌های برقرارشده با منبع /apps با یا بدون اسلش رو به جلو انتهایی (/apps یا /apps/**) استفاده می‌کند:

<Condition>(proxy.pathsuffix JavaRegex "/apps(/?)") and (request.verb = "POST")</Condition>

برای اطلاعات بیشتر درباره این نوع شرط، به چگونه بدون درنظر گرفتن ...مطابقت دهیم در انجمن Apigee مراجعه کنید.

مدل‌سازی نشانی‌های وب سلسله‌مراتبی

در برخی موارد، منابع API سلسله‌مراتبی خواهید داشت. برای مثال، «میانای برنامه‌سازی کاربردی سرویس‌های توسعه‌دهنده» روشی برای فهرست کردن همه برنامه‌های متعلق به یک توسعه‌دهنده ارائه می‌دهد. مسیر URI این است:

/developers/{developer_email}/apps

ممکن است منابعی داشته باشید که در آن‌ها برای هر نهاد در مجموعه، شناسه یکتایی تولید می‌شود که گاهی اوقات به‌صورت زیر حاشیه‌نویسی می‌شود:

/genus/:id/species

این مسیر به‌طور یکسان برای دو نشانی وب زیر اعمال می‌شود:

/genus/18904/species
/genus/17908/species

برای نمایش این ساختار در منبع API، می‌توانید از کارت‌های جوکر استفاده کنید. برای مثال:

/developers/*/apps
/developers/*example.com/apps
/genus/*/species

این نشانی‌های وب سلسله‌مراتبی را به‌درستی به‌عنوان منابع API حل‌وفصل خواهد کرد.

در برخی موارد، به‌ویژه برای میاناهای برنامه‌سازی کاربردی بسیار سلسله‌مراتبی، ممکن است بخواهید همه چیز زیر یک قطعه نشانی وب خاص را حل‌وفصل کنید. برای انجام این کار، از کارت عام دوتایی در تعریف منبع خود استفاده کنید. برای مثال، اگر منبع API زیر را تعریف کنید:
/developers/**

آن منبع API مسیرهای URI زیر را حل خواهد کرد:

/developers/{developer_email}/apps
/developers/{developer_email}/keys
/developers/{developer_email}/apps/{app_id}/keys

شرط جاری‌سازی شرطی در تعریف پراکسی API به این شکل است:

<Condition>(proxy.pathsuffix MatchesPath "/developers/**") and (request.verb = "POST")</Condition>

مثال‌های بیشتر

شرط پیوست‌شده به «قانون مسیر»

<RouteRule name="default">
 <!--this routing executes if the header indicates that this is an XML call. If true, the call is routed to the endpoint XMLTargetEndpoint-->
  <Condition>request.header.content-type = "text/xml"</Condition>
  <TargetEndpoint>XmlTargetEndpoint</TargetEndpoint>
</RouteRule>

شرایط پیوست‌شده به خط‌مشی

<Step>
<!--the policy MaintenancePolicy only executes if the response status code is exactly 503-->
  <Condition>response.status.code = 503</Condition>
  <Name>MaintenancePolicy</Name>
</Step>

جریان شرطی

<!-- this entire flow is executed only if the request verb is a GET-->
<Flow name="GetRequests">
  <Condition>request.verb="GET"</Condition>
  <Request>
    <Step>
<!-- this policy only executes if request path includes a term like statues-->
<Condition>request.path ~ "/statuses/**"</Condition>
      <Name>StatusesRequestPolicy</Name>
    </Step>
  </Request>
  <Response>
    <Step>
<!-- this condition has multiple expressions. The policy executes if the response code status is exactly 503 or 400-->
<Condition>(response.status.code = 503) or (response.status.code = 400)</Condition>
      <Name>MaintenancePolicy</Name>
    </Step>
  </Response>
</Flow>

اپراتورهای نمونه در شرایط

در اینجا چند نمونه از اپراتورهایی که برای ایجاد شرایط استفاده می‌شوند آورده شده است:

  • request.header.content-type = "text/xml"
  • request.header.content-length < 4096 && request.verb = "PUT"
  • response.status.code = 404 || response.status.code = 500
  • request.uri MatchesPath "/*/statuses/**"
  • request.queryparam.q0 NotEquals 10

مثال عملی: «/» را در انتهای مسیر نادیده بگیرید

توسعه‌دهندگان Edge معمولاً می‌خواهند هر دو پسوند مسیر زیر را مدیریت کنند: «/cat» و «/cat/». دلیل این است که برخی‌از کاربران یا کارخواه‌ها ممکن است «میانای برنامه‌سازی کاربردی» شما را با اسلش اضافی در انتهای مسیر فراخوانی کنند و شما باید بتوانید این مورد را در عبارت‌های شرطی خود مدیریت کنید. این مورد استفاده دقیق در «انجمن Apigee» مورد بحث قرار گرفته است.

اگر ترجیح می‌دهید، می‌توانید بدون استفاده از «عبارت باقاعده» به این هدف برسید:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>((proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

این گزینه خوبی است. واضح و خوانا باشد.

با «عبارت باقاعده» هم می‌توانید همین کار را انجام دهید، اما به‌این‌صورت. از پرانتز برای گروه‌بندی بخش عبارت باقاعده استفاده می‌شود، اما الزامی نیست.

<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>

تماس‌های میانای برنامه‌سازی کاربردی:

‫GET http://artomatic-test.apigee.net/matchtest/cat
or

GET http://artomatic-test.apigee.net/matchtest/cat/

آیا خط‌مشی اجرا می‌شود؟ بله. توجه داشته باشید که در عبارت باقاعده، نویسه «?» به این معنی است: با صفر یا یک نویسه قبلی مطابقت داشته باشد. بنابراین، هم «/cat» و هم «/cat/» مطابقت دارند.

فراخوانی میانای برنامه‌سازی کاربردی:

GET http://artomatic-test.apigee.net/matchtest/cat/spotted

آیا خط‌مشی اجرا می‌شود؟ نه. عبارت باقاعده با صفر یا فقط یک مورد از نویسه قبلی مطابقت دارد و هیچ چیز دیگری مجاز نیست.

تطبیق رشته‌های قراردادی با JavaRegex

در همه مثال‌های این موضوع، نشان می‌دهیم که چگونه یکی از متغیرهای جریان داخلی را مطابقت دهیم: proxy.pathsuffix. خوب است بدانید که می‌توانید تطبیق الگو را روی هر رشته یا متغیر جریان دلخواهی انجام دهید، چه متغیر جریان داخلی مثل proxy.pathsuffix باشد چه نباشد.

برای مثال، اگر شرایطی دارید که رشته‌ای اختیاری را آزمایش می‌کند، شاید رشته‌ای که در بار مفید زیرینه برگردانده شده است، یا رشته‌ای که از جستجوی سرور اصالت‌سنجی برگردانده شده است، می‌توانید از عملگرهای تطبیق برای آزمایش آن استفاده کنید. اگر از JavaRegex استفاده می‌کنید، عبارت باقاعده با کل رشته موضوع مقایسه خواهد شد. اگر موضوع «abc» باشد و عبارت باقاعده «[a-z]» باشد، هیچ تطابقی وجود ندارد، زیرا «[a-z]» دقیقاً با یک نویسه الفبایی مطابقت دارد. عبارت «[a-z]+» و همچنین «[a-z]*» و «[a-z]{3}» کار می‌کنند.

بیایید به یک مثال ملموس نگاه کنیم. فرض کنید سرور اصالت‌سنجی فهرستی از نقش‌ها را به‌صورت رشته‌ای با جداساز کاما برمی‌گرداند: «editor, author, guest».

برای آزمایش وجود نقش ویرایشگر، این ساختار کار نخواهد کرد، زیرا «ویرایشگر» فقط بخشی از کل رشته است.

<Condition>returned_roles ~~ "editor"</Condition>

بااین‌حال، این ساختار کار خواهد کرد:

<Condition>returned_roles ~~ ".*\beditor\b.*")</Condition>

این کار می‌کند زیرا شکست‌های کلمه و هر بخش دیگری از رشته را با پیشوند و پسوند .* درنظر می‌گیرد.

در این مثال، می‌توانید بااستفاده از عامل «مطابقت‌ها» برای «ویرایشگر» نیز آزمایش کنید:

<Condition>returned_roles ~~ "*editor*")</Condition>

بااین‌حال، در مواردی که به دقت بیشتری نیاز دارید، JavaRegex اغلب انتخاب بهتری است.

علامت نقل‌قول دوتایی در عبارت‌های JavaRegex

نحو «شرط» به عبارت JavaRegex نیاز دارد که در نقل‌قول‌های دوگانه پیچیده شود؛ بنابراین، اگر عبارت Regex دارید که شامل نقل‌قول‌های دوگانه است، به روشی جایگزین برای مطابقت دادن آن‌ها نیاز دارید. پاسخ این است: یونی‌کد. برای مثال، فرض کنید سرصفحه‌ای را ارسال می‌کنید که شامل نقل‌قول‌های دوتایی است، مانند سرصفحه زیر:
 -H 'content-type:multipart/related; type="application/xop+xml"'
اگر بخواهید آن سرایند را در شرط «عبارت باقاعده» مطابقت دهید، خطای «شرط نامعتبر» دریافت خواهید کرد زیرا عبارت شامل گیومه‌های دوتایی است:
request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"
راه‌حل این است که علامت نقل‌قول دوتایی مبتنی بر ASCII را با معادل آن در یونی‌کد، \u0022، جایگزین کنید. برای مثال، عبارت زیر معتبر است و نتیجه موردانتظار را تولید می‌کند:
request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"