Thêm tính năng hỗ trợ CORS vào một proxy API

Bạn đang xem tài liệu về Apigee Edge.
Chuyển đến tài liệu về Apigee X.
thông tin

CORS (Chia sẻ tài nguyên nhiều nguồn gốc) là một cơ chế tiêu chuẩn cho phép các lệnh gọi JavaScript XMLHttpRequest (XHR) được thực thi trên một trang web tương tác với các tài nguyên từ các miền không phải nguồn gốc. CORS là một giải pháp thường được triển khai cho "chính sách cùng nguồn gốc" được thực thi trên tất cả các trình duyệt. Ví dụ: nếu bạn thực hiện lệnh gọi XHR đến API Twitter từ việc thực thi mã JavaScript trong trình duyệt, thì lệnh gọi sẽ không thành công. Lý do là miền phân phát trang đến trình duyệt không giống với miền phân phát trang Twitter API. CORS mang đến giải pháp cho vấn đề này bằng cách cho phép các máy chủ "chọn tham gia" nếu muốn cung cấp tính năng chia sẻ tài nguyên trên nhiều nguồn gốc.

Video: Xem video ngắn để tìm hiểu cách bật CORS trên proxy API.

Trường hợp sử dụng điển hình của CORS

Mã JQuery sau đây gọi một dịch vụ mục tiêu giả định. Nếu được thực thi từ bên trong ngữ cảnh của một trình duyệt (trang web), lệnh gọi sẽ không thành công do chính sách cùng nguồn gốc:

<script>
var url = "http://service.example.com";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This is where we end up!
            }
    });
  });
});
</script>

Có một giải pháp cho vấn đề này là tạo một proxy API Apigee gọi API dịch vụ trên hệ thống phụ trợ. Hãy nhớ rằng Edge nằm giữa ứng dụng (trong trường hợp này là trình duyệt) và API phụ trợ (dịch vụ). Vì proxy API thực thi trên máy chủ chứ không phải trong trình duyệt, nên proxy API có thể gọi dịch vụ thành công. Sau đó, bạn chỉ cần đính kèm các tiêu đề CORS vào phản hồi TargetEndpoint. Miễn là trình duyệt hỗ trợ CORS, các tiêu đề này sẽ báo hiệu cho trình duyệt rằng bạn có thể "thư giãn" chính sách cùng nguồn gốc, cho phép lệnh gọi API nhiều nguồn gốc thành công.

Sau khi tạo proxy có hỗ trợ CORS, bạn có thể gọi URL proxy API thay vì dịch vụ phụ trợ trong mã phía máy khách. Ví dụ:

<script>
var url = "http://myorg-test.apigee.net/v1/example";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This time, we do not end up here!
            }
    });
  });
});
</script>

Đính kèm chính sách Thêm CORS vào một proxy API mới

Bạn có thể thêm tính năng hỗ trợ CORS vào một proxy API bằng cách đính kèm chính sách "Add CORS" (Thêm CORS) vào proxy API khi tạo proxy. Để thêm chính sách này, hãy chọn hộp đánh dấu Add CORS header (Thêm tiêu đề CORS) trên trang Bảo mật của trình hướng dẫn Build a Proxy.

Khi bạn chọn hộp đánh dấu này, một chính sách có tên là Add CORS (Thêm CORS) sẽ tự động được thêm vào hệ thống và được đính kèm vào quy trình trước phản hồi TargetEndpoint, như trong hình sau:

Thêm chính sách CORS đã được thêm vào trình điều hướng trong phần Chính sách và được đính kèm vào quy trình trước phản hồi TargetEndpoint khi kéo sang phải

Chính sách Thêm CORS được triển khai dưới dạng AssignMessage chính sách. Chính sách này sẽ thêm các tiêu đề thích hợp vào phản hồi. Về cơ bản, tiêu đề cho phép trình duyệt biết trình duyệt sẽ chia sẻ tài nguyên với nguồn gốc nào, phương thức nào chấp nhận, v.v. Bạn có thể đọc thêm về các tiêu đề CORS này trong Đề xuất về W3C về việc chia sẻ tài nguyên trên nhiều nguồn gốc.

Bạn nên sửa đổi chính sách như sau:

  • Thêm các tiêu đề content-typeauthorization (cần thiết để hỗ trợ phương thức xác thực cơ bản hoặc OAuth2) vào tiêu đề Access-Control-Allow-Headers, như trong phần trích dẫn mã dưới đây.
  • Để xác thực OAuth2, có thể bạn cần phải thực hiện các bước để khắc phục hành vi không tuân thủ RFC.
  • Bạn nên sử dụng <Set> để thiết lập các tiêu đề CORS thay vì <Add>, như minh hoạ trong phần trích dẫn bên dưới. Khi sử dụng <Add>, nếu tiêu đề Access-Control-Allow-Origin đã tồn tại, bạn sẽ gặp lỗi sau:

    The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

    Để biết thêm thông tin, hãy xem phần Lỗi CORS : tiêu đề chứa nhiều giá trị "*, *", nhưng chỉ được phép có một giá trị.

<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Set>
        <Headers>
            <Header name="Access-Control-Allow-Origin">{request.header.origin}</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, content-type, authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
        </Headers>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

Thêm các tiêu đề CORS vào một proxy hiện có

Bạn cần tạo chính sách Chỉ định thông báo mới theo cách thủ công và sao chép mã cho chính sách Thêm CORS được liệt kê trong phần trước vào đó. Sau đó, hãy đính kèm chính sách này vào quy trình trước phản hồi của TargetEndpoint của proxy API. Bạn có thể sửa đổi các giá trị tiêu đề nếu cần. Để biết thêm thông tin về cách tạo và đính kèm chính sách, hãy xem bài viết Chính sách là gì?.

Xử lý các yêu cầu kiểm tra CORS

Quá trình kiểm tra coroutine là việc gửi một yêu cầu tới một máy chủ để xác minh xem máy chủ đó có hỗ trợ CORS hay không. Các phản hồi kiểm tra thông thường bao gồm nguồn gốc mà máy chủ sẽ chấp nhận yêu cầu CORS, danh sách phương thức HTTP được hỗ trợ cho các yêu cầu CORS, tiêu đề có thể được dùng như một phần của yêu cầu tài nguyên, phản hồi kiểm tra thời gian tối đa sẽ được lưu vào bộ nhớ đệm và các tiêu đề khác. Nếu dịch vụ không cho biết có hỗ trợ CORS hoặc không muốn chấp nhận các yêu cầu nhiều nguồn gốc từ nguồn gốc của ứng dụng, thì chính sách trên nhiều nguồn gốc của trình duyệt sẽ được thực thi và mọi yêu cầu trên nhiều miền được thực hiện từ ứng dụng khách để tương tác với các tài nguyên được lưu trữ trên máy chủ đó sẽ không thành công.

Thông thường, các yêu cầu kiểm tra CORS được thực hiện bằng phương thức OPTIONS HTTP. Khi một máy chủ hỗ trợ CORS nhận được yêu cầu OPTIONS, máy chủ sẽ trả về một tập hợp các tiêu đề CORS cho ứng dụng để cho biết mức độ hỗ trợ của CORS. Nhờ sự bắt tay này, ứng dụng sẽ biết nội dung được phép yêu cầu từ miền không phải nguồn gốc.

Để biết thêm thông tin về quy trình kiểm tra, hãy tham khảo Đề xuất về việc chia sẻ tài nguyên W3C trên nhiều nguồn gốc. Ngoài ra, còn có nhiều blog và bài viết trên CORS để bạn tham khảo.

Apigee không có giải pháp kiểm tra CORS nào ngay từ đầu, nhưng bạn có thể triển khai theo mô tả trong phần này. Mục tiêu là để proxy đánh giá yêu cầu OPTIONS trong luồng có điều kiện. Sau đó, proxy có thể gửi lại phản hồi thích hợp cho ứng dụng.

Hãy xem một quy trình mẫu, sau đó thảo luận về các phần xử lý yêu cầu kiểm tra:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Response>
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
        </Flow>
    </Flows>

    <PreFlow name="PreFlow">
        <Request/>
        <Response/>

    </PreFlow>
    <HTTPProxyConnection>
        <BasePath>/v1/cnc</BasePath>
        <VirtualHost>default</VirtualHost>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
   </RouteRule>
   <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</ProxyEndpoint>

Sau đây là các phần chính của ProxyEndpoint này:

  • Tuyến Quy tắc được tạo cho mục tiêu NULL với điều kiện cho yêu cầu OPTIONS. Xin lưu ý rằng bạn chưa chỉ định TargetEndpoint. Nếu nhận được yêu cầu OPTIONS và các tiêu đề của yêu cầu Origin và Access-Control-Request-Method không rỗng, proxy sẽ ngay lập tức trả về các tiêu đề CORS trong một phản hồi cho ứng dụng khách (bỏ qua mục tiêu "máy chủ phụ trợ" mặc định thực tế). Để biết thông tin chi tiết về điều kiện luồng và TuyếnRule, hãy xem phần Điều kiện có biến luồng.

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    
  • Một quy trình OptionsPreFlight được tạo sẽ thêm chính sách Thêm CORS (chứa các tiêu đề CORS) vào luồng nếu nhận được yêu cầu OPTIONS và tiêu đề của yêu cầu Origin và Access-Control-Request-Method không rỗng.

     <Flow name="OptionsPreFlight">
                <Request/>
                <Response>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Response>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>
    

Sử dụng giải pháp CORS mẫu

Bạn có thể tìm thấy giải pháp CORS mẫu (được triển khai dưới dạng luồng dùng chung) trên GitHub. Nhập gói luồng được chia sẻ vào môi trường của bạn và đính kèm gói đó bằng cách sử dụng hook luồng hoặc trực tiếp vào luồng proxy API. Để biết thông tin chi tiết, hãy xem tệp CORS-Shared-FLow README đi kèm với mẫu.