热门角色不仅是灵感来源,更是你的效率助手。通过精挑细选的角色提示词,你可以快速生成高质量内容、提升创作灵感,并找到最契合你需求的解决方案。让创作更轻松,让价值更直接!
我们根据不同用户需求,持续更新角色库,让你总能找到合适的灵感入口。
本提示词专门用于生成符合现代JavaScript最佳实践的fetch请求代码。它能够根据不同的应用场景和需求,生成包含错误处理、数据格式转换、请求配置等完整功能的网络请求代码。支持GET、POST、PUT、DELETE等多种HTTP方法,可自定义请求头、超时设置和认证信息,确保生成的代码具备良好的可读性、可维护性和错误处理能力,适用于前端开发、API调用和数据交互等多种业务场景。
/**
* Modern fetch wrapper for POSTing JSON to ExampleAI text generation API
* - Bearer token auth
* - Timeout with AbortController
* - Exponential backoff retries for transient errors (429/5xx, network)
* - Robust error normalization and response parsing (JSON/text)
*
* Works in modern browsers and Node.js >= 18 (built-in fetch).
*/
/** @typedef {{status:number, statusText:string, url:string, method:string, requestId?:string, headers:Record<string,string>, body?:unknown}} HTTPErrorMeta */
class HTTPError extends Error {
/**
* @param {string} message
* @param {HTTPErrorMeta} meta
*/
constructor(message, meta) {
super(message);
this.name = 'HTTPError';
this.status = meta.status;
this.statusText = meta.statusText;
this.url = meta.url;
this.method = meta.method;
this.headers = meta.headers;
this.requestId = meta.requestId;
this.body = meta.body;
}
}
/**
* Safe JSON parse with fallback to text.
* @param {Response} res
* @returns {Promise<{ data: any, rawText?: string }>}
*/
async function parseBody(res) {
const contentType = res.headers.get('content-type') || '';
const isJSON = contentType.includes('application/json');
if (isJSON) {
try {
const data = await res.json();
return { data };
} catch (e) {
// Fallthrough to text if JSON malformed
}
}
const rawText = await res.text();
let data = rawText;
if (isJSON) {
// If declared as JSON but failed to parse, preserve text for diagnostics
data = { parseError: true, raw: rawText };
}
return { data, rawText };
}
/**
* Normalize response headers to a simple object.
* @param {Headers} headers
*/
function headersToObject(headers) {
const obj = {};
headers.forEach((v, k) => {
obj[k.toLowerCase()] = v;
});
return obj;
}
/**
* Determine if an HTTP status is transient and worth retrying.
* @param {number} status
*/
function isTransientStatus(status) {
// 429 Too Many Requests, 408 Request Timeout, 5xx Server Errors
return status === 429 || status === 408 || (status >= 500 && status < 600);
}
/**
* Parse Retry-After header to milliseconds if present.
* @param {Headers} headers
*/
function parseRetryAfterMs(headers) {
const v = headers.get('retry-after');
if (!v) return undefined;
const seconds = Number(v);
if (!Number.isNaN(seconds)) return Math.max(0, seconds * 1000);
const date = new Date(v).getTime();
if (!Number.isNaN(date)) {
const ms = date - Date.now();
return ms > 0 ? ms : 0;
}
}
/**
* Sleep helper with optional jitter.
* @param {number} ms
* @param {boolean} jitter
*/
function sleep(ms, jitter = true) {
if (ms <= 0) return Promise.resolve();
const jittered = jitter ? Math.round(ms * (0.8 + Math.random() * 0.4)) : ms;
return new Promise((r) => setTimeout(r, jittered));
}
/**
* Connect a user-provided AbortSignal to our controller, so either can cancel.
* @param {AbortController} controller
* @param {AbortSignal | undefined} userSignal
* @returns {() => void} cleanup
*/
function linkAbortSignals(controller, userSignal) {
if (!userSignal) return () => {};
const onAbort = () => {
if (!controller.signal.aborted) {
try {
controller.abort(userSignal.reason ?? new DOMException('Aborted', 'AbortError'));
} catch {
controller.abort();
}
}
};
if (userSignal.aborted) onAbort();
userSignal.addEventListener('abort', onAbort, { once: true });
return () => userSignal.removeEventListener('abort', onAbort);
}
/**
* Core fetch with timeout + retry.
* @param {string} url
* @param {RequestInit & { method?: string }} options
* @param {{ timeoutMs?: number, retries?: number, backoffBaseMs?: number, backoffFactor?: number }} cfg
* @returns {Promise<Response>}
*/
async function fetchWithTimeoutAndRetry(url, options, cfg = {}) {
const {
timeoutMs = 15000,
retries = 2,
backoffBaseMs = 400,
backoffFactor = 2,
} = cfg;
let attempt = 0;
let lastError;
while (attempt <= retries) {
const controller = new AbortController();
const cleanupLink = linkAbortSignals(controller, options.signal);
const timeoutId = setTimeout(() => {
// Timeout: abort request
try {
controller.abort(new DOMException('Timeout', 'AbortError'));
} catch {
controller.abort();
}
}, timeoutMs);
try {
const res = await fetch(url, { ...options, signal: controller.signal });
clearTimeout(timeoutId);
cleanupLink();
if (res.ok) return res;
// Non-OK: read body safely and maybe retry if transient
const { data } = await parseBody(res);
if (isTransientStatus(res.status) && attempt < retries) {
const retryAfter = parseRetryAfterMs(res.headers);
const delay = retryAfter ?? backoffBaseMs * Math.pow(backoffFactor, attempt);
await sleep(delay, true);
attempt += 1;
continue;
}
const meta = {
status: res.status,
statusText: res.statusText,
url,
method: (options.method || 'GET').toUpperCase(),
requestId: res.headers.get('x-request-id') || res.headers.get('x-requestid') || undefined,
headers: headersToObject(res.headers),
body: data,
};
const message = `HTTP ${meta.status} ${meta.statusText} for ${meta.method} ${meta.url}`;
throw new HTTPError(extractErrorMessage(data) || message, meta);
} catch (err) {
clearTimeout(timeoutId);
cleanupLink();
// Abort or network errors might be retryable
const isAbort = err && typeof err === 'object' && err.name === 'AbortError';
const isNetwork = err instanceof TypeError && !isAbort; // fetch network error in browsers/Node often TypeError
const canRetry = (isAbort || isNetwork) && attempt < retries;
lastError = err;
if (canRetry) {
const delay = backoffBaseMs * Math.pow(backoffFactor, attempt);
await sleep(delay, true);
attempt += 1;
continue;
}
throw err;
}
}
// Exceeded attempts
throw lastError;
}
/**
* Try to extract a meaningful error message from server payload.
* @param {any} data
*/
function extractErrorMessage(data) {
if (!data) return '';
if (typeof data === 'string') return data.slice(0, 500);
if (typeof data.message === 'string') return data.message;
if (data.error && typeof data.error === 'object') {
if (typeof data.error.message === 'string') return data.error.message;
if (typeof data.error.code === 'string') return `${data.error.code}`;
}
return '';
}
/**
* Build headers for JSON request with Bearer auth.
* @param {string} token
* @param {Record<string, string>} [extra]
*/
function buildJSONHeaders(token, extra = {}) {
const headers = new Headers(extra);
if (token) headers.set('Authorization', `Bearer ${token}`);
headers.set('Accept', 'application/json');
headers.set('Content-Type', 'application/json');
return headers;
}
/**
* Safe JSON stringify that drops undefined and functions.
* @param {any} obj
*/
function safeStringify(obj) {
return JSON.stringify(
obj,
(_, v) => {
if (typeof v === 'function' || typeof v === 'undefined') return undefined;
if (typeof v === 'bigint') return v.toString();
return v;
}
);
}
/**
* Generate text via ExampleAI API.
* @param {{
* token: string, // Bearer token (do not hardcode in client)
* payload: Record<string, any>, // Request JSON body expected by the API
* timeoutMs?: number,
* retries?: number,
* fetchOptions?: Partial<RequestInit> // e.g., { signal, integrity, referrerPolicy }
* }} params
* @returns {Promise<{ data: any, response: Response }>}
*/
export async function generateText({ token, payload, timeoutMs = 15000, retries = 2, fetchOptions = {} }) {
if (!token || typeof token !== 'string') {
throw new Error('Missing Bearer token. Provide a valid token via "token" parameter.');
}
if (!payload || typeof payload !== 'object') {
throw new Error('Invalid payload. Provide a JSON-serializable object in "payload".');
}
const url = 'https://api.exampleai.com/v1/text/generate';
const options = {
method: 'POST',
// Never cache POST requests with credentials; rely on server-side caching if any
cache: 'no-store',
credentials: 'omit', // Since we use Bearer token, do not send cookies by default
redirect: 'follow',
keepalive: false,
headers: buildJSONHeaders(token, fetchOptions.headers || {}),
body: safeStringify(payload),
// Allow caller-provided options like signal, referrerPolicy, integrity
...fetchOptions,
// Ensure our headers/body override fetchOptions in case of conflicts
headers: buildJSONHeaders(token, fetchOptions.headers || {}),
body: safeStringify(payload),
};
const res = await fetchWithTimeoutAndRetry(url, options, {
timeoutMs,
retries,
backoffBaseMs: 400,
backoffFactor: 2,
});
const { data } = await parseBody(res);
return { data, response: res };
}
// Optional: small convenience wrapper that returns only parsed data
export async function generateTextData(params) {
const { data } = await generateText(params);
return data;
}
import { generateTextData } from './exampleai.js';
// token 由服务端安全下发(例如通过 HTTP-only Cookie 换取临时 Bearer,或在 SSR 中注入)
const token = window.__EXAMPLEAI_TOKEN__;
const data = await generateTextData({
token,
payload: {
model: 'exampleai-text-1',
prompt: 'Write a haiku about autumn wind.',
max_tokens: 128,
temperature: 0.7,
// user: 'user-123', // 如 API 支持用户追踪,可传
},
timeoutMs: 12000,
retries: 2,
});
console.log('Generated:', data);
import { generateText } from './exampleai.js';
const token = process.env.EXAMPLEAI_API_KEY; // 不要硬编码在代码仓库
try {
const { data, response } = await generateText({
token,
payload: {
model: 'exampleai-text-1',
prompt: 'Summarize the benefits of typed JavaScript.',
max_tokens: 200,
temperature: 0.4,
},
timeoutMs: 15000,
retries: 3,
fetchOptions: {
// 可选:绑定外部取消信号
// signal: abortController.signal,
referrerPolicy: 'no-referrer',
},
});
console.log('status:', response.status);
console.log('result:', data);
} catch (err) {
// 详见下方“错误处理”
console.error(err);
}
const ac = new AbortController();
const p = generateTextData({
token,
payload: { model: 'exampleai-text-1', prompt: '...' },
fetchOptions: { signal: ac.signal },
});
setTimeout(() => ac.abort(), 3000); // 3 秒后主动取消
await p; // 将抛出 AbortError
try {
const { data } = await generateText({ token, payload });
// 使用 data
} catch (err) {
if (err instanceof HTTPError) {
// 服务器返回的详细错误
console.error('HTTPError:', {
status: err.status,
requestId: err.requestId,
body: err.body,
});
if (err.status === 401 || err.status === 403) {
// 引导刷新凭证或跳转登录
} else if (err.status === 429) {
// 可提示用户稍后重试
}
} else if (err && err.name === 'AbortError') {
console.warn('Request aborted (timeout or user cancel)');
} else {
// 网络错误或其他未知异常
console.error('Network/Unknown error:', err);
}
}
/**
* 安全、健壮的 GET + URLSearchParams + API Key 认证的 fetch 实现
* - 使用 AbortController 实现超时控制
* - 支持网络错误与 429/5xx 的指数重试(带抖动),遵循 Retry-After
* - 对响应进行内容类型探测并安全解析(JSON/Text)
* - 不硬编码 API Key,支持自定义认证头与认证前缀
*/
class TimeoutError extends Error {
constructor(message = 'Request timed out') {
super(message);
this.name = 'TimeoutError';
}
}
class HTTPError extends Error {
constructor(response, body) {
super(`HTTP ${response.status} ${response.statusText}`);
this.name = 'HTTPError';
this.status = response.status;
this.statusText = response.statusText;
this.body = body; // 服务器返回的错误主体(已解析)
}
}
/**
* 将对象或 URLSearchParams 规范化为 URLSearchParams
* - 忽略 undefined/null
* - 对数组值进行多次 append(key, v)
*/
function toURLSearchParams(input) {
if (input instanceof URLSearchParams) return input;
const usp = new URLSearchParams();
if (input && typeof input === 'object') {
for (const [k, v] of Object.entries(input)) {
if (v === undefined || v === null) continue;
if (Array.isArray(v)) {
for (const item of v) {
if (item !== undefined && item !== null) usp.append(k, String(item));
}
} else {
usp.append(k, String(v));
}
}
}
return usp;
}
/**
* 解析响应体:优先 JSON,其次 Text;其他类型将回退为 Text
*/
async function parseBody(response) {
const contentType = (response.headers.get('content-type') || '').toLowerCase();
try {
if (contentType.includes('application/json')) {
return await response.json();
}
if (contentType.startsWith('text/')) {
return await response.text();
}
// 非常规类型回退到 text(避免在不同运行时下的 Blob/ArrayBuffer 差异)
return await response.text();
} catch {
// 解析失败时保证不会再次抛错
return null;
}
}
/**
* 解析 Retry-After 头部(秒或 HTTP 日期)
*/
function parseRetryAfter(retryAfter) {
if (!retryAfter) return null;
const secMatch = retryAfter.trim().match(/^\d+$/);
if (secMatch) return parseInt(secMatch[0], 10) * 1000;
const date = Date.parse(retryAfter);
if (!Number.isNaN(date)) {
const ms = date - Date.now();
return ms > 0 ? ms : 0;
}
return null;
}
/**
* 计算重试延时(指数退避 + 抖动),并尊重 Retry-After
*/
function computeRetryDelay({ base = 500, cap = 5000, attempt = 0, response }) {
// 优先使用服务端的 Retry-After
if (response && (response.status === 429 || response.status === 503)) {
const retryAfter = response.headers.get('retry-after');
const fromHeader = parseRetryAfter(retryAfter);
if (fromHeader !== null) return Math.min(fromHeader, 30_000); // 保护上限 30s
}
const exp = Math.min(cap, base * Math.pow(2, attempt)); // 指数退避
const jitter = Math.floor(Math.random() * 250); // 0-250ms 抖动
return exp + jitter;
}
/**
* 判断是否为“可能可重试”的网络层错误
* - 浏览器中 fetch 的网络错误常为 TypeError
*/
function isLikelyTransientNetworkError(err) {
return err && (err.name === 'FetchError' || err instanceof TypeError);
}
/**
* GET 请求封装:对 https://text.example.net/summarize 发起请求
* @param {Object} options
* @param {Object|URLSearchParams} options.params - 查询参数(将被编码为 URLSearchParams)
* @param {string} options.apiKey - API Key(不要在前端硬编码,建议运行时安全注入)
* @param {string} [options.apiKeyHeader='Authorization'] - 认证头名称(如 'Authorization' 或 'X-API-Key')
* @param {string|null} [options.apiKeyScheme='Bearer'] - 认证前缀(如 'Bearer';传 null 表示不加前缀)
* @param {number} [options.timeout=10000] - 超时时间(毫秒)
* @param {number} [options.retries=2] - 最大重试次数(仅对网络错误/超时/特定 4xx/5xx 生效)
* @param {number} [options.retryBaseDelay=500] - 初始重试基准延时(毫秒)
* @param {string} [options.baseURL='https://text.example.net/summarize'] - 基础 URL
* @param {AbortSignal} [options.signal] - 外部取消信号
* @param {Function} [options.fetchImpl] - 自定义 fetch 实现(默认取全局 fetch)
* @returns {Promise<{ data: any, response: Response }>}
*/
async function fetchSummarize({
params,
apiKey,
apiKeyHeader = 'Authorization',
apiKeyScheme = 'Bearer',
timeout = 10_000,
retries = 2,
retryBaseDelay = 500,
baseURL = 'https://text.example.net/summarize',
signal,
fetchImpl,
} = {}) {
const fetchFn = fetchImpl || (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : null);
if (!fetchFn) {
throw new Error('Global fetch is not available. Provide options.fetchImpl in non-browser environments.');
}
const usp = toURLSearchParams(params);
const url = new URL(baseURL);
// 保留原有查询的基础上合并(若 baseURL 已带查询参数)
if (url.search) {
const existing = new URLSearchParams(url.search);
for (const [k, v] of usp.entries()) existing.append(k, v);
url.search = existing.toString();
} else {
url.search = usp.toString();
}
const headers = new Headers({
Accept: 'application/json, text/plain;q=0.8, */*;q=0.5',
});
if (apiKey) {
const value = apiKeyScheme ? `${apiKeyScheme} ${apiKey}` : apiKey;
headers.set(apiKeyHeader, value);
}
// 构建超时控制
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(new TimeoutError(`Request timeout after ${timeout}ms`)), timeout);
// 将外部 signal 的取消传递到内部
if (signal) {
if (signal.aborted) {
controller.abort(signal.reason);
} else {
signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true });
}
}
const requestInit = {
method: 'GET',
headers,
// 对跨域严格遵守 CORS,不做任何绕过行为
mode: 'cors',
cache: 'no-store',
credentials: 'omit', // 如需发送跨站 Cookie,请改为 'include' 且确保服务器允许
redirect: 'follow',
signal: controller.signal,
};
const RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]);
let attempt = 0;
try {
while (true) {
try {
const response = await fetchFn(url.toString(), requestInit);
if (!response.ok) {
const errorBody = await parseBody(response);
const httpError = new HTTPError(response, errorBody);
if (attempt < retries && RETRYABLE_STATUS.has(response.status)) {
const delay = computeRetryDelay({
base: retryBaseDelay,
attempt,
response,
});
await new Promise((r) => setTimeout(r, delay));
attempt += 1;
continue;
}
throw httpError;
}
const data = await parseBody(response);
return { data, response };
} catch (err) {
// AbortError 与 TimeoutError 不默认重试(可按需调整)
if (err instanceof TimeoutError || err?.name === 'AbortError') {
if (attempt < retries) {
const delay = computeRetryDelay({ base: retryBaseDelay, attempt });
await new Promise((r) => setTimeout(r, delay));
attempt += 1;
continue;
}
throw err;
}
// 其他网络层错误可有限次重试
if (isLikelyTransientNetworkError(err) && attempt < retries) {
const delay = computeRetryDelay({ base: retryBaseDelay, attempt });
await new Promise((r) => setTimeout(r, delay));
attempt += 1;
continue;
}
throw err;
}
}
} finally {
clearTimeout(timeoutId);
}
}
// 可选:导出默认函数(在模块环境下)
// export default fetchSummarize;
// 推荐:从安全的后端接口获取短期令牌或使用同源后端代理,而非将长效 API Key 暴露在浏览器
async function getRuntimeToken() {
// 例如:从同源后端换取一次性/短期 token
const res = await fetch('/api/token', { credentials: 'same-origin' });
if (!res.ok) throw new Error('Failed to get token');
const { token } = await res.json();
return token;
}
(async () => {
const token = await getRuntimeToken();
const params = new URLSearchParams({
text: '在这里放需要摘要的文本内容',
max_sentences: '3',
lang: 'zh',
});
try {
const { data, response } = await fetchSummarize({
params,
apiKey: token,
apiKeyHeader: 'Authorization',
apiKeyScheme: 'Bearer',
timeout: 8000,
retries: 2,
});
console.log('Status:', response.status);
console.log('Data:', data);
} catch (err) {
// 参考文末“错误处理”部分
console.error('Summarize request failed:', err);
}
})();
// Node 18+ 原生支持 fetch。确保在服务端持有并保护 API Key。
import fs from 'node:fs'; // 仅示例:可用于读取文件或日志等
(async () => {
const params = {
text: '面向生产环境的稳健 fetch 封装示例',
max_sentences: 2,
};
try {
const { data } = await fetchSummarize({
params,
apiKey: process.env.TEXT_API_KEY, // 从环境变量注入
apiKeyHeader: 'X-API-Key', // 假设服务端采用该头部
apiKeyScheme: null, // 不加 Bearer 前缀,直接发送 key 值
timeout: 10000,
retries: 3,
});
console.log('Summarize:', data);
} catch (err) {
console.error('Server-side summarize failed:', err);
}
})();
const controller = new AbortController();
fetchSummarize({
params: { text: '需要摘要的文本' },
apiKey: await getRuntimeToken(),
signal: controller.signal,
}).catch((err) => {
if (err.name === 'AbortError') {
console.log('Request cancelled');
} else {
console.error(err);
}
});
// 某些条件满足时取消
controller.abort();
示例捕获:
try {
const result = await fetchSummarize({ params: { text: '...' }, apiKey: await getRuntimeToken() });
console.log(result.data);
} catch (err) {
if (err instanceof TimeoutError) {
// 提示超时
} else if (err.name === 'AbortError') {
// 用户取消
} else if (err instanceof HTTPError) {
// 根据 err.status 做分支
console.error('HTTP', err.status, err.body);
} else {
// 其他网络/运行时错误
console.error('Unexpected error', err);
}
}
/**
* PATCH text to the compose/continue endpoint with Basic Auth, robust timeout and error handling.
*
* Target: https://writer.example.org/v2/compose/continue
* Method: PATCH
* Request Body: text/plain; charset=utf-8
* Auth: Basic (username:password), sent in Authorization header
*
* This function is runtime-agnostic: works in modern browsers and Node.js 18+ (native fetch).
*/
/**
* Encode "username:password" to Base64 (UTF-8 safe) for Basic Auth.
* Avoids btoa non-ASCII issues; uses Buffer in Node or TextEncoder+btoa in browsers.
*/
function toBase64Utf8(str) {
// Node.js path
if (typeof Buffer !== 'undefined' && typeof Buffer.from === 'function') {
return Buffer.from(str, 'utf-8').toString('base64');
}
// Browser path
const encoder = new TextEncoder();
const bytes = encoder.encode(str);
let binary = '';
const chunkSize = 0x8000; // prevent call stack overflow on large payloads
for (let i = 0; i < bytes.length; i += chunkSize) {
binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
}
if (typeof btoa === 'function') {
return btoa(binary);
}
throw new Error('Base64 encoding is not supported in this environment.');
}
/**
* Build the Basic Authorization header value.
*/
function buildBasicAuthHeader(username, password) {
if (!username || !password) {
throw new Error('Missing Basic Auth credentials: username and password are required.');
}
const token = toBase64Utf8(`${username}:${password}`);
return `Basic ${token}`;
}
/**
* Parse HTTP response into { data, raw, contentType }.
* - JSON -> object
* - Text/others -> string
* - 204/205 -> null data
*/
async function parseResponse(response) {
const contentType = response.headers.get('content-type') || '';
if (response.status === 204 || response.status === 205) {
return { data: null, raw: '', contentType };
}
try {
if (contentType.includes('application/json')) {
const json = await response.json();
return { data: json, raw: JSON.stringify(json), contentType };
}
const text = await response.text();
return { data: text, raw: text, contentType };
} catch (e) {
// Fallback: treat as text if parsing fails
const text = await response.text().catch(() => '');
return { data: text, raw: text, contentType };
}
}
/**
* Create a normalized error for non-2xx HTTP responses and network/timeout failures.
*/
function createHttpError({ message, name = 'HTTPError', response, url, body, cause }) {
const err = new Error(message);
err.name = name;
if (response) {
err.status = response.status;
err.statusText = response.statusText;
}
err.url = url;
if (body !== undefined) err.body = body; // parsed body (json or text)
if (cause) err.cause = cause;
return err;
}
/**
* PATCH text to a URL with Basic Auth using fetch.
*
* @param {Object} params
* @param {string} params.url - Target URL (e.g., https://writer.example.org/v2/compose/continue)
* @param {string} params.text - Plain text payload to send in request body
* @param {string} params.username - Basic auth username
* @param {string} params.password - Basic auth password
* @param {number} [params.timeout=15000] - Timeout in ms (abort the request if exceeded)
* @param {Object} [params.extraHeaders] - Optional additional headers (won’t override required ones)
* @returns {Promise<{status:number, ok:boolean, headers:Headers, data:any, contentType:string|null}>}
*/
async function patchTextWithBasicAuth({
url,
text,
username,
password,
timeout = 15000,
extraHeaders = {},
}) {
if (!url) throw new Error('Parameter "url" is required.');
if (typeof text !== 'string') {
throw new Error('Parameter "text" must be a string for text/plain payload.');
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeout);
// Build headers
const headers = new Headers({
'Content-Type': 'text/plain; charset=utf-8',
Accept: 'application/json, text/plain;q=0.9, */*;q=0.8',
Authorization: buildBasicAuthHeader(username, password),
...extraHeaders, // allow safe extension (won’t override above keys if extraHeaders uses same case)
});
const requestInit = {
method: 'PATCH',
headers,
body: text,
// CORS-safe defaults. Do not send cookies by default for cross-origin.
mode: 'cors',
credentials: 'omit',
redirect: 'follow',
cache: 'no-store',
signal: controller.signal,
};
let response;
try {
response = await fetch(url, requestInit);
} catch (cause) {
clearTimeout(timer);
if (cause && cause.name === 'AbortError') {
throw createHttpError({
message: `Request timed out after ${timeout} ms`,
name: 'TimeoutError',
url,
cause,
});
}
throw createHttpError({
message: 'Network error or CORS failure while performing fetch()',
name: 'NetworkError',
url,
cause,
});
} finally {
clearTimeout(timer);
}
const { data, raw, contentType } = await parseResponse(response);
if (!response.ok) {
// Construct a meaningful message with snippets (avoid logging sensitive data)
const snippet =
typeof data === 'string'
? data.slice(0, 300)
: JSON.stringify(data).slice(0, 300);
let friendly = `HTTP ${response.status} ${response.statusText}`;
if (response.status === 401) friendly += ' (authentication failed)';
if (response.status === 403) friendly += ' (forbidden)';
if (response.status === 429) friendly += ' (rate limited)';
if (response.status >= 500) friendly += ' (server error)';
const err = createHttpError({
message: `${friendly}. URL: ${url}`,
response,
url,
body: data,
});
err.contentType = contentType || null;
err.bodyPreview = snippet;
throw err;
}
return {
status: response.status,
ok: response.ok,
headers: response.headers,
data,
contentType: contentType || null,
};
}
(async () => {
// 请从安全来源注入凭据(示例中为占位值)
const USERNAME = '<your-username>'; // e.g., process.env.API_USER in Node
const PASSWORD = '<your-password>'; // e.g., process.env.API_PASS in Node
const url = 'https://writer.example.org/v2/compose/continue';
const textPayload = 'Continue writing from the previous draft.\nPlease add a concluding paragraph.';
try {
const result = await patchTextWithBasicAuth({
url,
text: textPayload,
username: USERNAME,
password: PASSWORD,
timeout: 12000,
extraHeaders: {
// 可选:例如自定义追踪 ID(非敏感)
'X-Request-ID': 'req-' + Date.now(),
},
});
// 根据响应类型处理
if (result.contentType?.includes('application/json')) {
console.log('JSON response:', result.data);
} else {
console.log('Text response:', result.data);
}
} catch (err) {
// 统一错误处理
console.error(`[${err.name}] ${err.message}`);
if (err.status) {
console.error('Status:', err.status, err.statusText);
console.error('Body preview:', err.bodyPreview);
}
// 可根据 err.name 分流:TimeoutError / NetworkError / HTTPError
}
})();
把“写网络请求”这件繁琐事,变成一次高质量的一键生成。通过让 AI 扮演资深 JS 工程师,快速产出可直接落地的 fetch 请求代码与说明,覆盖常见方法、认证、超时与错误兜底等关键场景,帮助你:1) 快速搭建稳定的接口层;2) 统一团队代码风格与错误处理策略;3) 显著减少重复劳动与低级问题;4) 降低首单接入与后续扩展成本;5) 以更安全、可维护的方式交付前端与数据交互能力。
几分钟内搭建标准化请求模块,自动补齐超时、错误提示与数据解析,统一代码风格,减少线上故障。
快速对接支付、登录、地图等外部服务,一键生成多种方法请求与认证配置,把时间留给业务逻辑。
生成适配弱网的请求封装,内置超时与重试策略,轻松处理文件上传下载与分页加载,显著提升稳定性。
将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。
把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。
在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。
半价获取高级提示词-优惠即将到期