簡單接口工具(ApiCraft-Web)

ApiCraft-Web

項目介紹

ApiCraft-Web 是一個輕量級的 API 測試工具,提供了簡潔直觀的界面,幫助開發者快速測試和調試 HTTP 接口。

功能特點

  • 支持多種 HTTP 請求方法(GET、POST、PUT、DELETE)
  • 可配置請求參數(Query Parameters)
  • 可配置請求頭(Headers)
  • JSON 格式的請求體編輯器,支持語法高亮和格式化
  • 美觀的響應數據展示
  • 顯示響應狀態碼、響應時間和數據大小
  • 跨域支持

技術棧

前端

  • Vue 3
  • TailwindCSS
  • CodeMirror 6
  • Axios

后端

  • Spring Boot 2.3.4
  • RestTemplate
  • Lombok

快速開始

環境要求

  • Node.js 14+
  • JDK 8+
  • Maven 3+

安裝和運行

  1. 克隆項目
git clone https://gitee.com/anxwefndu/ApiCraft-Web.git
cd ApiCraft-Web
  1. 啟動后端服務
cd SpringBoot
mvn spring-boot:run
  1. 啟動前端服務
cd code
npm install
npm run serve
  1. 訪問應用
    打開瀏覽器訪問:http://localhost:8081

使用說明

  1. 發送請求

    • 選擇請求方法(GET、POST、PUT、DELETE)
    • 輸入目標 URL
    • 根據需要添加查詢參數、請求頭和請求體
    • 點擊"發送請求"按鈕
  2. 查看響應

    • 響應狀態碼
    • 響應時間
    • 數據大小
    • 格式化的響應數據

開發計劃

  • 支持更多請求方法
  • 請求歷史記錄
  • 接口集合管理
  • 環境變量配置
  • 響應數據導出
  • 暗色主題支持

源碼下載

ApiCraft-Web

演示截圖

1.系統首頁
在這里插入圖片描述

2.接口請求
在這里插入圖片描述

核心源碼

code/src/App.vue

<script setup>
import {ref, reactive} from 'vue';
import axios from 'axios';
import Message from '@/utils/message';
import JsonEditor from '@/components/JsonEditor.vue';// 請求方法
const method = ref('GET');// 請求URL
const url = ref('');// 當前選中的參數類型標簽
const activeTab = ref('params'); // params, headers, body// 請求參數
const requestData = reactive({params: [{ key: '', value: '' }],headers: [{ key: 'Content-Type', value: 'application/json' },],body: ''
});// 響應數據
const response = reactive({status: '',time: '',size: '',data: null,loading: false
});// 添加參數
const addParam = () => {requestData.params.push({ key: '', value: '' });
};// 刪除參數
const removeParam = (index) => {requestData.params.splice(index, 1);
};// 添加請求頭
const addHeader = () => {requestData.headers.push({ key: '', value: '' });
};// 刪除請求頭
const removeHeader = (index) => {requestData.headers.splice(index, 1);
};// 切換參數類型標簽
const switchTab = (tab) => {activeTab.value = tab;
};const jsonEditor = ref();
const hasJsonError = ref(false);const formatJsonBody = () => {jsonEditor.value?.formatJson();
};const handleJsonError = (error) => {hasJsonError.value = !!error;
};// 發送請求
const sendRequest = async () => {if (!url.value) {Message.warning('請輸入請求URL');return;}if (hasJsonError.value) {Message.error('請求體 JSON 格式錯誤');return;}response.loading = true;try {// 構建請求參數const queryParams = {};const headers = {};requestData.params.forEach(param => {if (param.key && param.value) {queryParams[param.key] = param.value;}});requestData.headers.forEach(header => {if (header.key && header.value) {headers[header.key] = header.value;}});const requestBody = activeTab.value === 'body' ? requestData.body : null;// 發送請求到后端代理const result = await axios.post('http://localhost:8080/api/proxy', {url: url.value,method: method.value,headers: headers,queryParams: queryParams,body: requestBody});// 更新響應數據response.status = `${result.data.status} ${result.data.status === 200 ? 'OK' : ''}`;response.time = `${result.data.responseTime}ms`;response.size = result.data.contentLength;response.data = result.data.data;Message.success('請求成功');} catch (error) {Message.error(error.message || '請求失敗');response.status = '500 Error';response.data = error.message;} finally {response.loading = false;}
};// 添加格式化響應數據的函數
const formatResponseData = (data) => {if (typeof data === 'string') {try {// 嘗試解析字符串為 JSONreturn JSON.stringify(JSON.parse(data), null, 2);} catch {// 如果不是 JSON 字符串,直接返回原始字符串,去掉多余的引號return data.replace(/^"|"$/g, '');}}// 如果是對象,格式化為 JSONreturn JSON.stringify(data, null, 2);
};
</script><template><div class="bg-gray-50" style="width: 100%; height: 100%"><div class="w-[1200px] mx-auto"><nav class="h-16 bg-white shadow flex items-center justify-between px-8"><div class="flex items-center space-x-2"><span class="text-2xl font-['Pacifico'] text-primary">logo</span><span class="text-lg font-medium">API工具</span></div><button class="w-10 h-10 rounded-button flex items-center justify-center hover:bg-gray-100 transition-colors"><i class="fas fa-sun text-gray-600"></i></button></nav><main class="py-12"><div class="mx-auto"><div class="bg-white rounded-lg shadow p-8"><h2 class="text-lg font-semibold mb-4">接口測試</h2><div class="space-y-4"><div class="grid grid-cols-1 md:grid-cols-4 gap-4"><div><label class="block text-sm font-medium text-gray-700 mb-1">請求方法</label><div class="relative"><select v-model="method"class="block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-primary focus:border-primary rounded-button"><option>GET</option><option>POST</option><option>PUT</option><option>DELETE</option></select></div></div><div class="md:col-span-3"><label class="block text-sm font-medium text-gray-700 mb-1">請求URL</label><div class="flex"><input type="text" v-model="url"class="flex-1 min-w-0 block w-full px-3 py-2 rounded-l-button border border-gray-300 focus:outline-none focus:ring-primary focus:border-primary"><buttonclass="bg-primary hover:bg-blue-600 text-white px-4 py-2 rounded-r-button text-sm font-medium" @click="sendRequest">發送</button></div></div></div><div><label class="block text-sm font-medium text-gray-700 mb-1">請求參數</label><div class="overflow-hidden border border-gray-300 rounded-button"><div class="bg-gray-50 px-4 py-2 border-b border-gray-300"><div class="flex items-center space-x-4"><button class="text-sm font-medium text-gray-500" :class="activeTab === 'params' ? ' text-primary ' : ''" @click="switchTab('params')">Query Params</button><button class="text-sm font-medium text-gray-500" :class="activeTab === 'headers' ? ' text-primary ' : ''" @click="switchTab('headers')">Headers</button><button class="text-sm font-medium text-gray-500" :class="activeTab === 'body' ? ' text-primary ' : ''" @click="switchTab('body')">Body</button></div></div><div class="bg-white"><div class="space-y-3 p-4" v-show="activeTab === 'params'"><template v-for="(param, index) in requestData.params" :key="index"><div class="grid grid-cols-12 gap-4 items-center"><div class="col-span-3"><input type="text" v-model="param.key" placeholder="參數名"class="block w-full px-3 py-2 border border-gray-300 rounded-button focus:outline-none focus:ring-primary focus:border-primary"></div><div class="col-span-8"><input type="text" v-model="param.value" placeholder="參數值"class="block w-full px-3 py-2 border border-gray-300 rounded-button focus:outline-none focus:ring-primary focus:border-primary"></div><div class="col-span-1"><button class="text-gray-500 hover:text-gray-700" @click="removeParam(index)"><i class="fas fa-trash fa-icon"></i></button></div></div></template><button class="text-sm text-primary hover:text-blue-600 flex items-center space-x-1"><i class="fas fa-plus fa-icon"></i><span @click="addParam">添加參數</span></button></div><div class="space-y-3 p-4" v-show="activeTab === 'headers'"><template v-for="(header, index) in requestData.headers" :key="index"><div class="grid grid-cols-12 gap-4 items-center"><div class="col-span-3"><input type="text" v-model="header.key" placeholder="參數名"class="block w-full px-3 py-2 border border-gray-300 rounded-button focus:outline-none focus:ring-primary focus:border-primary"></div><div class="col-span-8"><input type="text" v-model="header.value" placeholder="參數值"class="block w-full px-3 py-2 border border-gray-300 rounded-button focus:outline-none focus:ring-primary focus:border-primary"></div><div class="col-span-1"><button class="text-gray-500 hover:text-gray-700" @click="removeHeader(index)"><i class="fas fa-trash fa-icon"></i></button></div></div></template><button class="text-sm text-primary hover:text-blue-600 flex items-center space-x-1"><i class="fas fa-plus fa-icon"></i><span @click="addHeader">添加請求頭</span></button></div><div class="space-y-3" v-if="activeTab === 'body'"><JsonEditorv-model="requestData.body"height="500px"ref="jsonEditor"@error="handleJsonError"/><div class="flex justify-end space-x-2" style="margin-bottom: 0.75rem; margin-right: 0.75rem"><button@click="formatJsonBody"class="text-sm text-primary hover:text-blue-600 flex items-center space-x-1"><i class="fas fa-code fa-icon"></i><span>格式化</span></button></div></div></div></div></div><div><label class="block text-sm font-medium text-gray-700 mb-1">響應結果</label><div v-if="response.data" class="border border-gray-300 rounded-button overflow-hidden"><div class="bg-gray-50 px-4 py-2 border-b border-gray-300 flex items-center justify-between"><div class="flex items-center space-x-2"><span class="text-sm font-medium">狀態: {{ response.status }}</span><span class="text-sm text-gray-500">時間: {{ response.time }}</span><span class="text-sm text-gray-500">大小: {{ response.size }}</span></div><button @click="sendRequest" class="text-sm text-primary hover:text-blue-600"><i class="fas fa-redo fa-icon mr-1"></i><span>重新請求</span></button></div><div class="bg-white p-4"><pre class="whitespace-pre-wrap">{{ formatResponseData(response.data) }}</pre></div></div></div></div></div><div class="mt-12 bg-white rounded-lg shadow p-8"><h2 class="text-xl font-medium mb-6">使用說明</h2><div class="space-y-4 text-gray-600"><div class="flex items-start space-x-3"><div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5"><i class="fas fa-check text-sm text-primary"></i></div><p>在請求 URL 輸入框中輸入完整的 API 地址,選擇對應的請求方法(GET、POST、PUT、DELETE)</p></div><div class="flex items-start space-x-3"><div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5"><i class="fas fa-check text-sm text-primary"></i></div><p>在請求參數區域可以設置 Query 參數、Headers 以及請求體(Body),支持多個參數的添加和刪除</p></div><div class="flex items-start space-x-3"><div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5"><i class="fas fa-check text-sm text-primary"></i></div><p>發送請求后,可以在響應結果區域查看狀態碼、響應時間、數據大小等信息,支持重新發送請求</p></div><div class="flex items-start space-x-3"><div class="w-6 h-6 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0 mt-0.5"><i class="fas fa-check text-sm text-primary"></i></div><p>響應數據會以格式化的 JSON 形式展示,方便查看和分析接口返回的數據結構</p></div></div></div></div></main></div></div>
</template><style>
body {min-height: 100vh;
}#app {min-height: 100vh;
}body::-webkit-scrollbar {width: 15px;
}body::-webkit-scrollbar-track {background: #f1f5f9;border-radius: 8px;
}body::-webkit-scrollbar-thumb {background: #6366f1;border-radius: 8px;border: 2px solid #f1f5f9;
}body::-webkit-scrollbar-thumb:hover {background: #4f46e5;
}
</style>

SpringBoot/src/main/java/com/boot/service/ApiService.java

package com.boot.service;import com.boot.model.ApiRequest;
import com.boot.model.ApiResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;import java.util.Map;@Service
public class ApiService {private final RestTemplate restTemplate;public ApiService() {this.restTemplate = new RestTemplate();}public ApiResponse executeRequest(ApiRequest request) {long startTime = System.currentTimeMillis();ApiResponse response = new ApiResponse();try {// 構建請求頭HttpHeaders headers = new HttpHeaders();if (request.getHeaders() != null) {request.getHeaders().forEach(headers::add);}// 構建URL(包含查詢參數)UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(request.getUrl());if (request.getQueryParams() != null) {for (Map.Entry<String, String> entry : request.getQueryParams().entrySet()) {builder.queryParam(entry.getKey(), entry.getValue());}}// 構建請求實體HttpEntity<?> httpEntity = new HttpEntity<>(request.getBody(), headers);// 不要對 URL 組件進行編碼String finalUrl = builder.build(false).toUri().toString();// 修改執行請求部分,使用 String.class 接收響應ResponseEntity<String> responseEntity = restTemplate.exchange(finalUrl,HttpMethod.valueOf(request.getMethod().toUpperCase()),httpEntity,String.class);// 設置響應信息response.setStatus(responseEntity.getStatusCodeValue());// 嘗試將響應轉換為 JSON 對象String responseBody = responseEntity.getBody();try {ObjectMapper mapper = new ObjectMapper();Object jsonData = mapper.readValue(responseBody, Object.class);response.setData(jsonData);} catch (JsonProcessingException e) {// 如果不是 JSON 格式,直接返回字符串response.setData(responseBody);}response.setResponseTime(System.currentTimeMillis() - startTime);response.setContentLength(responseEntity.getHeaders().getContentLength() != -1? responseEntity.getHeaders().getContentLength() + " bytes": "unknown");} catch (Exception e) {e.printStackTrace();response.setStatus(500);String message = e.getMessage();if (message.contains("[")) {response.setData(message.substring(message.indexOf("[")));}response.setResponseTime(System.currentTimeMillis() - startTime);}return response;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/77180.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/77180.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/77180.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Git進階操作

Git高階操作完全指南&#xff1a;解鎖專業開發工作流 前言 在當今的軟件開發領域&#xff0c;掌握高級Git技能已成為區分普通開發者與專業開發者的關鍵因素。根據最新的GitHub數據&#xff0c;熟練應用交互式暫存和Rebase等高級功能的開發者&#xff0c;其代碼審查通過率平均提…

Python結合AI生成圖像藝術作品代碼及介紹

為實現生成圖像藝術作品&#xff0c;我選用 Stable Diffusion 庫結合 Python 編寫代碼。下面先展示代碼&#xff0c;再詳細介紹其原理、模塊及使用方法等內容。 生成圖片代碼 import torch from diffusers import StableDiffusionPipeline# 加載預訓練模型 pipe StableDiffu…

Linux操作系統--靜態庫和動態庫的生成and四種解決加載找不到動態庫的四種方法

目錄 必要的知識儲備&#xff1a; 生成靜態庫&#xff1a; 生成動態庫&#xff1a; 解決加載找不到動態庫的四種方法&#xff1a; 第一種&#xff1a;拷貝到系統默認的庫路徑 /usr/lib64/ 第二種&#xff1a;在系統默認的庫路徑/usr/lib64/下建立軟鏈接 第三種&#xff1…

LLM中的N-Gram、TF-IDF和Word embedding

文章目錄 1. N-Gram和TF-IDF&#xff1a;通俗易懂的解析1.1 N-Gram&#xff1a;讓AI學會"猜詞"的技術1.1.1 基本概念1.1.2 工作原理1.1.3 常見類型1.1.4 應用場景1.1.5 優缺點 1.2 TF-IDF&#xff1a;衡量詞語重要性的尺子1.2.1 基本概念1.2.2 計算公式1.2.3 為什么需…

Leetcode 3359. 查找最大元素不超過 K 的有序子矩陣【Plus題】

1.題目基本信息 1.1.題目描述 給定一個大小為 m x n 的二維矩陣 grid。同時給定一個 非負整數 k。 返回滿足下列條件的 grid 的子矩陣數量&#xff1a; 子矩陣中最大的元素 小于等于 k。 子矩陣的每一行都以 非遞增 順序排序。 矩陣的子矩陣 (x1, y1, x2, y2) 是通過選擇…

如何在 Ubuntu 22.04 上安裝、配置、使用 Nginx

如何在 Ubuntu 22.04 上安裝、配置、使用 Nginx&#xff1f;-阿里云開發者社區 更新應用 sudo apt updatesudo apt upgrade檢查必要依賴并安裝 sudo apt install -y curl gnupg2 ca-certificates lsb-release安裝nginx sudo apt install -y nginx# 啟動nginx sudo systemct…

Linux:顯示 -bash-4.2$ 問題(CentOS 7)

文章目錄 一、原因二、錯誤示例三、解決辦法 一、原因 在 CentOS 7 系統中&#xff0c;如果你看到命令行提示符顯示為 -bash-4.2$&#xff0c;一般是 Bash shell 正在運行&#xff0c;并且它沒有找到用戶的個人配置文件&#xff0c;或者這些文件有問題而未能成功加載。這個提示…

QT6 源(34):隨機數生成器類 QRandomGenerator 的源碼閱讀

&#xff08;1&#xff09;代碼來自 qrandom.h &#xff0c;結合官方的注釋&#xff1a; #ifndef QRANDOM_H #define QRANDOM_H#include <QtCore/qalgorithms.h> #include <algorithm> // for std::generate #include <random> // for std::mt1993…

第二篇:linux之Xshell使用及相關linux操作

第二篇&#xff1a;linux之Xshell使用及相關linux操作 文章目錄 第二篇&#xff1a;linux之Xshell使用及相關linux操作一、Xshell使用1、Xshell安裝2、Xshell使用 二、Bash Shell介紹與使用1、什么是Bash Shell(殼)&#xff1f;2、Bash Shell能干什么&#xff1f;3、平時如何使…

MCP(模型上下文協議)學習筆記

學習MCP&#xff08;模型上下文協議&#xff09;的系統化路徑&#xff0c;結合技術原理、工具實踐和社區資源&#xff0c;幫助你高效掌握這一AI交互標準&#xff1a; 在當今人工智能飛速發展的時代&#xff0c;AI技術正以前所未有的速度改變著我們的生活和工作方式。然而&#…

MIR-2025 | 多模態知識助力機器人導航:從復雜環境到高效路徑規劃

作者&#xff1a;Hui Yuan, Yan Huang, Zetao Du, Naigong Yu, Ziqi Liu, Dongbo Zhang, Kun Zhang 單位&#xff1a;北京工業大學信息科學與技術學院&#xff0c;北京工業大學計算智能與智能系統北京市重點實驗室&#xff0c;中科院自動化研究所模式識別國家重點實驗室與多智…

javaSE.泛型界限

現在有一個新的需求&#xff0c;沒有String類型成績了&#xff0c;但是成績依然可能是整數&#xff0c;也可能是小數&#xff0c;這是我們不希望用戶將泛型指定為除數字類型外的其他類型&#xff0c;我們就需要使用到泛型的上界定義&#xff1a; 上界&#x1f447;只能使用其本…

壓縮包網頁預覽(zip-html-preview)

zip-html-preview 項目介紹 這是一個基于 Spring Boot 開發的在線 ZIP 文件預覽工具,主要用于預覽 ZIP 壓縮包中的 HTML 文件及其相關資源。 主要功能 支持拖拽上傳或點擊選擇多個 ZIP 文件自動解壓并提取 ZIP 文件中的 HTML 文件在線預覽 HTML 文件及其相關的 CSS、JavaSc…

QML之Overlay

Overlay&#xff08;覆蓋層&#xff09;是QML中用于在當前界面之上顯示臨時內容的重要組件。 一、Overlay基礎概念 1.1 什么是Overlay&#xff1f; Overlay是一種浮動在現有界面之上的視覺元素&#xff0c;具有以下特點&#xff1a; 臨時顯示&#xff0c;不影響底層布局 通…

iso17025證書申請方法?iso17025認證意義

ISO/IEC 17025證書申請方法 ISO/IEC 17025是檢測和校準實驗室能力的國際標準&#xff0c;申請CNAS認可的流程如下&#xff1a; 1. 前期準備 標準學習&#xff1a;深入理解ISO/IEC 17025:2017標準要求。 差距分析&#xff1a;評估現有實驗室管理與技術能力與標準的差距。 制…

reverse3 1(Base加密)

題目 做法 下載安裝包&#xff0c;解壓&#xff0c;把解壓后的文件拖進Exeinfo PE進行分析 32位&#xff0c;無殼 扔進IDA&#xff08;32位&#xff09;&#xff0c;找到main&#xff0c;F5反編譯 只是因為在人群中多看了你一眼——第31行的right flag&#xff0c;關鍵詞找到…

電控---CMSIS概覽

1. CMSIS庫簡介 CMSIS&#xff08;Cortex Microcontroller Software Interface Standard&#xff0c;Cortex微控制器軟件接口標準&#xff09;是由ARM公司開發的一套標準化軟件接口&#xff0c;旨在為基于ARM Cortex-M系列處理器&#xff08;如Cortex-M0/M0/M3/M4/M7/M33等&am…

list.

列表類型是用來存儲多個有序的字符串&#xff0c;列表中的每個字符串稱為元素&#xff08;element&#xff09;&#xff0c;?個列表最多可以存儲個元素 在 Redis 中&#xff0c;可以對列表兩端插入&#xff08;push&#xff09;和彈出&#xff08;pop&#xff09;&#xff0c;…

關于Diamond機械手的運動學與動力學的推導

1.關于Diamond機械手 &#xff08;1&#xff09;位置模型推導 逆解&#xff1a;機械末端平臺的位置與驅動關節之間的關系。 設p點在xy平面的坐標是&#xff08;x&#xff0c;y&#xff09;T&#xff0c;此時根據向量求解 OP等于向量r等于e向xy軸的向量主動臂長度向xy軸的向量…

如何新建一個空分支(不繼承 master 或任何提交)

一、需求分析&#xff1a; 在 Git 中&#xff0c;我們通常通過 git branch 來新建分支&#xff0c;這些分支默認都會繼承當前所在分支的提交記錄。但有時候我們希望新建一個“完全干凈”的分支 —— 沒有任何提交&#xff0c;不繼承 master 或任何已有內容&#xff0c;這該怎么…