跳转至

先进的创造

import got from '../../dist/source/index.js';

/*
* Got supports composing multiple instances together. This is very powerful.
*
* You can create a client that limits download speed,
*   then compose it with an instance that signs a request.
*
* It's like plugins without any of the plugin mess.
* You just create instances and then compose them together.
*
* To mix them use `instanceA.extend(instanceB, instanceC, ...)`, that's all.
* Let's begin.
*/

// Logging all `got(…)` calls
const logger = got.extend({
    handlers: [
        (options, next) => {
            console.log(`Sending ${options.method} to ${options.url}`);
            return next(options);
        }
    ]
});

// Denying redirects to foreign hosts
const controlRedirects = got.extend({
    hooks: {
        beforeRedirect: [
            (options, response) => {
                const {origin} = response.request.options.url;
                if (options.url.origin !== origin) {
                    throw new Error(`Redirection to ${options.url.origin} is not allowed from ${origin}`);
                }
            }
        ]
    }
});

// Limiting download & upload size
// This can prevent crashing due to insufficient memory
const limitDownloadUpload = got.extend({
    handlers: [
        (options, next) => {
            const {downloadLimit, uploadLimit} = options.context;
            let promiseOrStream = next(options);

            // A destroy function that supports both promises and streams
            const destroy = message => {
                if (options.isStream) {
                    promiseOrStream.destroy(new Error(message));
                    return;
                }

                promiseOrStream.cancel(message);
            };

            if (typeof downloadLimit === 'number') {
                promiseOrStream.on('downloadProgress', progress => {
                    if (progress.transferred > downloadLimit && progress.percent !== 1) {
                        destroy(`Exceeded the download limit of ${downloadLimit} bytes`);
                    }
                });
            }

            if (typeof uploadLimit === 'number') {
                promiseOrStream.on('uploadProgress', progress => {
                    if (progress.transferred > uploadLimit && progress.percent !== 1) {
                        destroy(`Exceeded the upload limit of ${uploadLimit} bytes`);
                    }
                });
            }

            return promiseOrStream;
        }
    ]
});

// No user agent
const noUserAgent = got.extend({
    headers: {
        'user-agent': undefined
    }
});

// Custom endpoint
const httpbin = got.extend({
    prefixUrl: 'https://httpbin.org/'
});

// Signing requests
import crypto from 'node:crypto';

const getMessageSignature = (data, secret) => crypto.createHmac('sha256', secret).update(data).digest('hex').toUpperCase();
const signRequest = got.extend({
    hooks: {
        beforeRequest: [
            options => {
                const secret = options.context.secret ?? process.env.SECRET;

                if (secret) {
                    options.headers['sign'] = getMessageSignature(options.body ?? '', secret);
                }
            }
        ]
    }
});

/*
* Putting it all together
*/
const merged = got.extend(
    noUserAgent,
    logger,
    limitDownloadUpload,
    httpbin,
    signRequest,
    controlRedirects
);

// There's no 'user-agent' header :)
const {headers} = await merged.post('anything', {
    body: 'foobar',
    context: {
        secret: 'password'
    }
}).json();

console.log(headers);
// Sending POST to https://httpbin.org/anything
// {
//   Accept: 'application/json',
//   'Accept-Encoding': 'gzip, deflate, br',
//   'Content-Length': '6',
//   Host: 'httpbin.org',
//   Sign: 'EB0167A1EBF205510BAFF5DA1465537944225F0E0140E1880B746F361FF11DCA'
// }

const MEGABYTE = 1048576;
await merged('https://pop-iso.sfo2.cdn.digitaloceanspaces.com/21.04/amd64/intel/5/pop-os_21.04_amd64_intel_5.iso', {
    context: {
        downloadLimit: MEGABYTE
    },
    prefixUrl: ''
});
// CancelError: Exceeded the download limit of 1048576 bytes