Browse Source

postman工具支持更丰富的示例

zxlie 1 month ago
parent
commit
85058e6bc3
7 changed files with 328 additions and 20 deletions
  1. 1 0
      README.md
  2. 2 1
      apps/manifest.json
  3. 0 1
      apps/options/index.js
  4. 11 3
      apps/postman/index.css
  5. 12 1
      apps/postman/index.html
  6. 150 14
      apps/postman/index.js
  7. 152 0
      apps/postman/sw.js

+ 1 - 0
README.md

@@ -12,6 +12,7 @@
 [![GitHub Stars](https://img.shields.io/github/stars/zxlie/FeHelper?style=for-the-badge&color=8b5cf6&logo=github)](https://github.com/zxlie/FeHelper)
 [![GitHub Forks](https://img.shields.io/github/forks/zxlie/FeHelper?style=for-the-badge&color=8b5cf6&logo=github)](https://github.com/zxlie/FeHelper)
 [![开发历史](https://img.shields.io/badge/since-2011-f59e0b?style=for-the-badge&logo=calendar&logoColor=white)](https://github.com/zxlie/FeHelper)
+![star](https://gitcode.com/zxlie/FeHelper/star/badge.svg)
 
 [🌐 官网地址](https://fehelper.com) • [📖 在线文档](https://fehelper.com/docs.html) • [💬 问题反馈](https://github.com/zxlie/FeHelper/issues) • [💰 FH$ 代币](https://www.gitfish.dev/repo/zxlie/FeHelper)
 

+ 2 - 1
apps/manifest.json

@@ -64,7 +64,8 @@
             "background/tools.js",
 
             "code-beautify/beautify.js",
-            "code-beautify/beautify-css.js"
+            "code-beautify/beautify-css.js",
+            "postman/sw.js"
         ],
         "matches": ["<all_urls>"]
       }

+ 0 - 1
apps/options/index.js

@@ -2,7 +2,6 @@ import Awesome from '../background/awesome.js'
 import MSG_TYPE from '../static/js/common.js';
 import Settings from './settings.js';
 import Statistics from '../background/statistics.js';
-import toolMap from '../background/tools.js';
 
 // 工具分类定义
 const TOOL_CATEGORIES = [

+ 11 - 3
apps/postman/index.css

@@ -92,15 +92,23 @@ textarea.form-control.f-param {
     z-index: 10000;
 }
 .x-xdemo,a.x-xdemo {
-    margin-left: 30px;
+    margin-left: 15px;
     font-size: 12px;
-    color: blue;
+    color: #007bff;
     cursor: pointer;
     text-decoration: underline;
     user-select: none;
+    padding: 2px 8px;
+    border-radius: 3px;
+    background-color: #f8f9fa;
+    border: 1px solid #dee2e6;
+    transition: all 0.2s ease;
 }
 .x-xdemo:hover {
-    text-decoration: underline;
+    text-decoration: none;
+    background-color: #e9ecef;
+    border-color: #007bff;
+    color: #0056b3;
 }
 .x-toolbar {
     margin:0;

+ 12 - 1
apps/postman/index.html

@@ -24,6 +24,15 @@
         </div>
         <div class="panel-body mod-endecode">
 
+            <!-- Mock服务器状态提示 -->
+            <div class="alert alert-info" style="margin-bottom: 15px; padding: 10px 15px; border-radius: 4px; background-color: #d1ecf1; border: 1px solid #bee5eb; color: #0c5460;">
+                <strong>🎉 本地Mock服务器已就绪!</strong> 
+                点击下方按钮快速体验本地POST请求测试,无需真实后端服务器。
+                <small style="display: block; margin-top: 5px; color: #6c757d;">
+                    💡 提示:Mock服务器基于Service Worker实现,支持JSON和表单数据格式
+                </small>
+            </div>
+
             <div class="row mod-inputs">
                 <div class="ui-mt-10">
                     <label for="url">接口地址:</label>
@@ -31,6 +40,8 @@
 
                     <span class="x-xdemo" @click="setDemo(1)">Get示例</span>
                     <span class="x-xdemo" @click="setDemo(2)">Post示例</span>
+                    <span class="x-xdemo" @click="setDemo(3)">Mock登录API</span>
+                    <span class="x-xdemo" @click="setDemo(4)">Mock数据API</span>
 
                 </div>
 
@@ -55,7 +66,7 @@
                     <label for="param">请求参数:</label>
                     <textarea type="text" v-model="paramContent" id="param" class="form-control f-param" placeholder="请输入参数"></textarea>
 
-                    <span class="x-xdemo" @click="transParamMode()">参数转<span v-html="paramMode==='kv'?'JSON':'URL-KV'">JSON</span>格式</span>
+                    <span class="x-xdemo" @click="transParamMode()">参数转<span v-html="paramModeText">JSON</span>格式</span>
                 </div>
 
                 <div class="ui-mt-10">

+ 150 - 14
apps/postman/index.js

@@ -22,6 +22,13 @@ new Vue({
         paramMode:'kv' // kv、json
     },
 
+    computed: {
+        // 计算属性:根据当前参数内容格式返回按钮文字
+        paramModeText() {
+            return this.detectParamFormat() === 'kv' ? 'JSON' : 'URL-KV';
+        }
+    },
+
     watch: {
         urlContent: function (val) {
             let url = val;
@@ -49,11 +56,17 @@ new Vue({
             },
             deep: true,
         },
+        // 监听参数内容变化,自动更新按钮文字
+        paramContent: function() {
+            // 触发计算属性重新计算
+            this.$forceUpdate();
+        }
     },
 
     mounted: function () {
         this.$refs.url.focus();
         this.loadPatchHotfix();
+        this.initMockServer();
     },
     methods: {
 
@@ -83,6 +96,31 @@ new Vue({
             });
         },
 
+        initMockServer() {
+            // 注册Service Worker用于Mock服务器
+            if ('serviceWorker' in navigator) {
+                window.addEventListener('load', () => {
+                    navigator.serviceWorker.register('./sw.js')
+                        .then((registration) => {
+                            console.log('✅ FeHelper Mock Server 已注册:', registration.scope);
+                            // 通知Vue组件Mock服务器已就绪
+                            window.dispatchEvent(new CustomEvent('mockServerReady'));
+                        })
+                        .catch((error) => {
+                            console.warn('❌ Mock Server 注册失败:', error);
+                        });
+                });
+            } else {
+                console.warn('❌ 当前浏览器不支持Service Worker');
+            }
+            
+            // 监听Mock服务器就绪事件
+            window.addEventListener('mockServerReady', () => {
+                console.log('🎉 Mock服务器已就绪,可以测试POST请求了!');
+                // 可以在这里添加一些UI提示
+            });
+        },
+
         postman: function () {
             this.$nextTick(() => {
                 this.sendRequest(this.urlContent, this.methodContent, this.paramContent);
@@ -145,24 +183,74 @@ new Vue({
         deleteHeader(event) {
             event.target.parentNode.remove();
         },
+        // 检测当前参数内容的数据格式
+        detectParamFormat() {
+            if (!this.paramContent || !this.paramContent.trim()) {
+                return 'kv'; // 默认为KV格式
+            }
+            
+            const content = this.paramContent.trim();
+            
+            // 检测是否为JSON格式
+            try {
+                JSON.parse(content);
+                return 'json';
+            } catch (e) {
+                // 检测是否为KV格式(包含=号且用&分隔)
+                if (content.includes('=') && (content.includes('&') || content.split('=').length === 2)) {
+                    return 'kv';
+                }
+                // 如果都不符合,默认为KV格式
+                return 'kv';
+            }
+        },
+
         transParamMode(){
-            if(this.paramMode === 'kv') {
+            // 先检测当前格式
+            const currentFormat = this.detectParamFormat();
+            
+            if(currentFormat === 'kv') {
                 this.paramMode = 'json';
                 let objParam = {};
-                this.paramContent.split('&').forEach(p => {
-                    let x = p.split('=');
-                    objParam[x[0]] = x[1];
-                });
-                this.paramContent = JSON.stringify(objParam,null,4);
+                
+                // 检查是否有内容
+                if (this.paramContent && this.paramContent.trim()) {
+                    this.paramContent.split('&').forEach(p => {
+                        if (p.trim()) {
+                            let x = p.split('=');
+                            if (x.length >= 2) {
+                                objParam[x[0].trim()] = x[1].trim();
+                            }
+                        }
+                    });
+                }
+                
+                // 如果没有任何参数,提供默认示例
+                if (Object.keys(objParam).length === 0) {
+                    objParam = {
+                        "key1": "value1",
+                        "key2": "value2",
+                        "key3": "value3"
+                    };
+                }
+                
+                this.paramContent = JSON.stringify(objParam, null, 4);
             }else{
                 this.paramMode = 'kv';
                 try {
-                    let obj = JSON.parse(this.paramContent);
-                    this.paramContent = Object.keys(obj).map(k => {
-                        let v = JSON.stringify(obj[k]).replace(/"/g,'');
-                        return `${k}=${v}`;
-                    }).join('&');
+                    if (this.paramContent && this.paramContent.trim()) {
+                        let obj = JSON.parse(this.paramContent);
+                        this.paramContent = Object.keys(obj).map(k => {
+                            let v = JSON.stringify(obj[k]).replace(/"/g,'');
+                            return `${k}=${v}`;
+                        }).join('&');
+                    } else {
+                        // 如果JSON为空,提供默认示例
+                        this.paramContent = 'key1=value1&key2=value2&key3=value3';
+                    }
                 } catch (e) {
+                    // JSON解析失败时,提供默认示例
+                    this.paramContent = 'key1=value1&key2=value2&key3=value3';
                 }
             }
         },
@@ -284,12 +372,60 @@ new Vue({
 
         setDemo: function (type) {
             if (type === 1) {
+                // GET示例
                 this.urlContent = 'http://t.weather.sojson.com/api/weather/city/101030100';
                 this.methodContent = 'GET';
-            } else {
-                this.urlContent = 'https://chrome.fehelper.com/test/post';
+                this.paramContent = '';
+                this.headerList = [new Date() * 1];
+            } else if (type === 2) {
+                // 基础Mock API
+                this.urlContent = window.location.origin + '/api/mock';
+                this.methodContent = 'POST';
+                this.paramContent = JSON.stringify({
+                    username: 'fehelper_user',
+                    password: '123456',
+                    email: '[email protected]',
+                    action: 'login',
+                    timestamp: new Date().toISOString()
+                }, null, 2);
+                
+                // 自动设置Content-Type为application/json
+                this.headerList = [new Date() * 1];
+                this.$nextTick(() => {
+                    $(`#header_key_${this.headerList[0]}`).val('Content-Type');
+                    $(`#header_value_${this.headerList[0]}`).val('application/json');
+                });
+            } else if (type === 3) {
+                // Mock登录API
+                this.urlContent = window.location.origin + '/api/user/login';
                 this.methodContent = 'POST';
-                this.paramContent = 'username=postman&password=123456'
+                this.paramContent = JSON.stringify({
+                    username: 'admin',
+                    password: 'admin123',
+                    remember: true
+                }, null, 2);
+                
+                this.headerList = [new Date() * 1];
+                this.$nextTick(() => {
+                    $(`#header_key_${this.headerList[0]}`).val('Content-Type');
+                    $(`#header_value_${this.headerList[0]}`).val('application/json');
+                });
+            } else if (type === 4) {
+                // Mock数据创建API
+                this.urlContent = window.location.origin + '/api/data/create';
+                this.methodContent = 'POST';
+                this.paramContent = JSON.stringify({
+                    title: '测试数据',
+                    content: '这是一个通过FeHelper Mock服务器创建的测试数据',
+                    category: 'test',
+                    tags: ['mock', 'test', 'fehelper']
+                }, null, 2);
+                
+                this.headerList = [new Date() * 1];
+                this.$nextTick(() => {
+                    $(`#header_key_${this.headerList[0]}`).val('Content-Type');
+                    $(`#header_value_${this.headerList[0]}`).val('application/json');
+                });
             }
         },
 

+ 152 - 0
apps/postman/sw.js

@@ -0,0 +1,152 @@
+/**
+ * FeHelper Postman Mock Server
+ * 基于Service Worker实现的本地POST请求模拟服务器
+ */
+
+// 模拟的API端点配置
+const MOCK_APIS = {
+  '/api/mock': {
+    method: 'POST',
+    response: {
+      success: true,
+      message: 'Mock服务器响应成功',
+      timestamp: new Date().toISOString(),
+      data: {
+        id: 1001,
+        name: 'FeHelper Mock API',
+        version: '1.0.0',
+        description: '这是一个基于Service Worker的模拟API服务器'
+      }
+    },
+    delay: 500 // 模拟网络延迟
+  },
+  '/api/user/login': {
+    method: 'POST',
+    response: {
+      success: true,
+      message: '登录成功',
+      token: 'mock_jwt_token_' + Date.now(),
+      user: {
+        id: 1001,
+        username: 'testuser',
+        email: '[email protected]',
+        role: 'admin'
+      }
+    },
+    delay: 300
+  },
+  '/api/data/create': {
+    method: 'POST',
+    response: {
+      success: true,
+      message: '数据创建成功',
+      id: Math.floor(Math.random() * 10000),
+      createdAt: new Date().toISOString()
+    },
+    delay: 800
+  }
+};
+
+// 监听fetch事件
+self.addEventListener('fetch', (event) => {
+  const url = new URL(event.request.url);
+  const pathname = url.pathname;
+  
+  // 检查是否是我们的Mock API端点
+  const mockApi = MOCK_APIS[pathname];
+  
+  if (mockApi && event.request.method === mockApi.method) {
+    event.respondWith(handleMockRequest(event.request, mockApi));
+  }
+});
+
+// 处理Mock请求
+async function handleMockRequest(request, mockApi) {
+  try {
+    // 模拟网络延迟
+    await new Promise(resolve => setTimeout(resolve, mockApi.delay));
+    
+    // 获取请求体数据
+    let requestData = null;
+    try {
+      const contentType = request.headers.get('content-type');
+      if (contentType && contentType.includes('application/json')) {
+        requestData = await request.json();
+      } else if (contentType && contentType.includes('application/x-www-form-urlencoded')) {
+        const formData = await request.text();
+        requestData = parseFormData(formData);
+      }
+    } catch (e) {
+      console.log('Mock Server: 无法解析请求体', e);
+    }
+    
+    // 构建响应数据
+    const responseData = {
+      ...mockApi.response,
+      request: {
+        method: request.method,
+        url: request.url,
+        headers: Object.fromEntries(request.headers.entries()),
+        body: requestData
+      },
+      server: {
+        name: 'FeHelper Mock Server',
+        version: '1.0.0',
+        poweredBy: 'Service Worker'
+      }
+    };
+    
+    // 返回响应
+    return new Response(JSON.stringify(responseData, null, 2), {
+      status: 200,
+      statusText: 'OK',
+      headers: {
+        'Content-Type': 'application/json; charset=utf-8',
+        'Access-Control-Allow-Origin': '*',
+        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
+        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
+        'X-Powered-By': 'FeHelper Mock Server',
+        'X-Response-Time': mockApi.delay + 'ms'
+      }
+    });
+    
+  } catch (error) {
+    // 错误响应
+    return new Response(JSON.stringify({
+      success: false,
+      error: 'Mock服务器内部错误',
+      message: error.message,
+      timestamp: new Date().toISOString()
+    }, null, 2), {
+      status: 500,
+      statusText: 'Internal Server Error',
+      headers: {
+        'Content-Type': 'application/json; charset=utf-8'
+      }
+    });
+  }
+}
+
+// 解析表单数据
+function parseFormData(formDataString) {
+  const params = new URLSearchParams(formDataString);
+  const result = {};
+  for (const [key, value] of params) {
+    result[key] = value;
+  }
+  return result;
+}
+
+// Service Worker安装事件
+self.addEventListener('install', (event) => {
+  console.log('FeHelper Mock Server: Service Worker 已安装');
+  self.skipWaiting();
+});
+
+// Service Worker激活事件
+self.addEventListener('activate', (event) => {
+  console.log('FeHelper Mock Server: Service Worker 已激活');
+  event.waitUntil(self.clients.claim());
+});
+
+console.log('FeHelper Mock Server: Service Worker 已加载');