Http_Response简介

我们传统的访问canister的方法是通过agent代理访问,需要在支持JavaScript的环境中正常运行。但其实canister还支持Http Request访问,只需要一个URL就可返回相应的数据。

由于边缘节点与canister之间单次请求有cycleLimit,所以小型数据可通过无callback的http_response方法直接返回,而大型数据需要分片后,通过含callback的http_response方法串行返回。

例如,我们可以通过https://${canisterId}.raw.ic0.app/fileA这个URL向canister发出/fileA的请求信息,canister可根据业务逻辑进行自定义数据返回。

核心代码(Types + http_request函数)

type HeaderField = (Text, Text);
type StreamingCallbackHttpResponse = {
    body: Blob;
    token: ?Token;
};
type Token = {}; // 对象类型,可根据需要添加参数
type StreamingStrategy = {
    #Callback: {
        callback: shared (Token) -> async (StreamingCallbackHttpResponse);
        token: Token;
    }
};
type HttpRequest =  {
    method: Text;
    url: Text;
    headers: [HeaderField];        
    body: Blob;
};
type HttpResponse = {
    status_code: Nat16;
    headers: [HeaderField];
    body: Blob;
    streaming_strategy: ?StreamingStrategy;
};

public query func http_request(request: HttpRequest): async HttpResponse{
    ...
};

示例-无回调(Callback)函数型

import Text "mo:base/Text";

// 仅解析url,无callback版本
actor http {
    type HeaderField = (Text, Text);
    type StreamingCallbackHttpResponse = {
        body: Blob;
        token: ?Token;
    };
    type Token = {};
    type StreamingStrategy = {
        #Callback: {
            callback: shared (Token) -> async (StreamingCallbackHttpResponse);
            token: Token;
        }
    };
    type HttpRequest =  {
        method: Text;
        url: Text; // 为ic0.app后的路径
        headers: [HeaderField];        
        body: Blob;
    };
    type HttpResponse = {
        status_code: Nat16;
        headers: [HeaderField];
        body: Blob;
        streaming_strategy: ?StreamingStrategy;
    };

    public query func http_request(request: HttpRequest): async HttpResponse {
        if(request.url == "/fileA") {
            {
                status_code = 200;
                headers = [];
                body = Text.encodeUtf8("I'm file A.");
                streaming_strategy = null;
            }
        } else {
            {
                status_code = 404;
                headers = [];
                body = Text.encodeUtf8("worng url");
                streaming_strategy = null;
            }
        }
    };
};

示例-回调(Callback)函数型

import Text "mo:base/Text";
import Blob "mo:base/Blob";

// callback版本
actor http {
    let ans: [Text] = ["A","B","C","D","E"];
    type HeaderField = (Text, Text);
    type StreamingCallbackHttpResponse = {
        body: Blob;
        token: ?CallbackToken;
    };
    type CallbackToken = {
        index: Nat;
    };
    type StreamingStrategy = {
        #Callback: {
            callback: query (CallbackToken) -> async (StreamingCallbackHttpResponse);
            token: CallbackToken;
        }
    };
    type HttpRequest =  {
        method: Text;
        url: Text;
        headers: [HeaderField];        
        body: Blob;
    };
    type HttpResponse = {
        status_code: Nat16;
        headers: [HeaderField];
        body: Blob;
        streaming_strategy: ?StreamingStrategy;
    };

    public query func streamingCallback(tk: CallbackToken): async StreamingCallbackHttpResponse{
        let (payload, token) = _workContent(tk.index, 3);
        {
            body = payload;
            token = token;
        }
    };

    private func _workContent(index: Nat,size: Nat): (Blob, ?CallbackToken) {
        let payload = Text.encodeUtf8(ans[index]);
        if(index == size) return (payload, null);
        (payload, ?{index = index + 1;})
    };

    public query func http_request(request: HttpRequest): async HttpResponse {
        if(request.url == "/text") {
            let (payload, token) = _workContent(1,3);
            {
                status_code = 200;
                headers = [("Content-Type", "txt")];
                body = payload;
                streaming_strategy = switch(token) {
                    case(null) {null;};
                    case(?tk) {
                        ?#Callback({
                            callback = streamingCallback;
                            token = tk;
                        })
                    }
                }
            }
        } else {
            {
                status_code = 404;
                headers = [];
                body = Text.encodeUtf8("worng url");
                streaming_strategy = null;
            }
        }
    };
};

——示例代码来自xiaoyuanxun,有删改。

— Motoko —

A Student on the way to full stack of Web3.