index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /**
  2. * FeHelper 简易版Postman
  3. */
  4. const JSON_SORT_TYPE_KEY = 'json_sort_type_key';
  5. new Vue({
  6. el: '#pageContainer',
  7. data: {
  8. urlContent: '',
  9. methodContent: 'GET',
  10. resultContent: '',
  11. funcName: '',
  12. paramContent: '',
  13. responseHeaders: [],
  14. jfCallbackName_start: '',
  15. jfCallbackName_end: '',
  16. errorMsgForJson: '',
  17. originalJsonStr: '',
  18. headerList: [new Date() * 1],
  19. urlencodedDefault: 1,
  20. urlParams: [],
  21. paramMode:'kv' // kv、json
  22. },
  23. watch: {
  24. urlContent: function (val) {
  25. let url = val;
  26. let reg = /[?&]([^?&#]+)=([^?&#]*)/g;
  27. let params = [];
  28. let ret = reg.exec(url);
  29. while (ret) {
  30. params.push({
  31. key: ret[1],
  32. value: ret[2],
  33. });
  34. ret = reg.exec(url);
  35. }
  36. const originStr = this.urlParams2String(params);
  37. const newStr = this.urlParams2String(this.urlParams);
  38. if (originStr !== newStr) {
  39. this.urlParams = params;
  40. }
  41. },
  42. urlParams: {
  43. handler(val) {
  44. this.urlContent =
  45. this.urlContent.substr(0, this.urlContent.indexOf("?") + 1) +
  46. val.map((item) => `${item.key}=${item.value}`).join("&");
  47. },
  48. deep: true,
  49. },
  50. },
  51. mounted: function () {
  52. this.$refs.url.focus();
  53. this.loadPatchHotfix();
  54. },
  55. methods: {
  56. loadPatchHotfix() {
  57. // 页面加载时自动获取并注入页面的补丁
  58. chrome.runtime.sendMessage({
  59. type: 'fh-dynamic-any-thing',
  60. thing: 'fh-get-tool-patch',
  61. toolName: 'postman'
  62. }, patch => {
  63. if (patch) {
  64. if (patch.css) {
  65. const style = document.createElement('style');
  66. style.textContent = patch.css;
  67. document.head.appendChild(style);
  68. }
  69. if (patch.js) {
  70. try {
  71. if (window.evalCore && window.evalCore.getEvalInstance) {
  72. window.evalCore.getEvalInstance(window)(patch.js);
  73. }
  74. } catch (e) {
  75. console.error('postman补丁JS执行失败', e);
  76. }
  77. }
  78. }
  79. });
  80. },
  81. postman: function () {
  82. this.$nextTick(() => {
  83. this.sendRequest(this.urlContent, this.methodContent, this.paramContent);
  84. });
  85. },
  86. sendRequest: function (url, method, body) {
  87. let xhr = new XMLHttpRequest();
  88. xhr.addEventListener("readystatechange", (resp) => {
  89. let result = 'Loading...';
  90. switch (resp.target.readyState) {
  91. case resp.target.OPENED:
  92. result = 'Senting...';
  93. break;
  94. case resp.target.HEADERS_RECEIVED:
  95. result = 'Headers received';
  96. this.responseHeaders = resp.target.getAllResponseHeaders().trim().split('\n').map(item => {
  97. return item.split(': ').map(x => x.trim())
  98. });
  99. break;
  100. case resp.target.LOADING:
  101. result = 'Loading...';
  102. break;
  103. case resp.target.DONE:
  104. try {
  105. result = JSON.stringify(JSON.parse(resp.target.responseText), null, 4);
  106. } catch (e) {
  107. result = resp.target.responseText;
  108. }
  109. this.jsonFormat(result);
  110. this.renderTab();
  111. break;
  112. }
  113. this.resultContent = result || '无数据';
  114. });
  115. xhr.open(method, url);
  116. let isPost = false;
  117. if (method.toLowerCase() === 'post') {
  118. isPost = true;
  119. this.urlencodedDefault && xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  120. }
  121. // 设置请求头:Header
  122. this.headerList.forEach(id => {
  123. let headerKey = $(`#header_key_${id}`).val();
  124. let headerVal = $(`#header_value_${id}`).val();
  125. if (headerKey && headerVal) {
  126. xhr.setRequestHeader(headerKey, headerVal);
  127. }
  128. });
  129. // 如果body是json格式的,需要转换成k-v格式
  130. try {
  131. let obj = JSON.parse(body);
  132. body = Object.keys(obj).map(k => {
  133. let v = JSON.stringify(obj[k]).replace(/"/g,'');
  134. return `${k}=${v}`;
  135. }).join('&');
  136. } catch (e) {
  137. }
  138. xhr.send(isPost && body);
  139. },
  140. addHeader() {
  141. this.headerList.push(new Date() * 1);
  142. },
  143. deleteHeader(event) {
  144. event.target.parentNode.remove();
  145. },
  146. transParamMode(){
  147. if(this.paramMode === 'kv') {
  148. this.paramMode = 'json';
  149. let objParam = {};
  150. this.paramContent.split('&').forEach(p => {
  151. let x = p.split('=');
  152. objParam[x[0]] = x[1];
  153. });
  154. this.paramContent = JSON.stringify(objParam,null,4);
  155. }else{
  156. this.paramMode = 'kv';
  157. try {
  158. let obj = JSON.parse(this.paramContent);
  159. this.paramContent = Object.keys(obj).map(k => {
  160. let v = JSON.stringify(obj[k]).replace(/"/g,'');
  161. return `${k}=${v}`;
  162. }).join('&');
  163. } catch (e) {
  164. }
  165. }
  166. },
  167. renderTab: function () {
  168. jQuery('#tabs').tabs({
  169. show: (event, ui) => {
  170. }
  171. });
  172. this.$refs.resultContainer.classList.remove('hide');
  173. },
  174. jsonFormat: function (source) {
  175. this.errorMsgForJson = '';
  176. this.jfCallbackName_start = '';
  177. this.jfCallbackName_end = '';
  178. if (!source) {
  179. return false;
  180. }
  181. // json对象
  182. let jsonObj = null;
  183. // 下面校验给定字符串是否为一个合法的json
  184. try {
  185. this.funcName = '';
  186. // 再看看是不是jsonp的格式
  187. let reg = /^([\w\.]+)\(\s*([\s\S]*)\s*\)$/igm;
  188. let matches = reg.exec(source);
  189. if (matches != null) {
  190. this.funcName = matches[1];
  191. source = matches[2];
  192. }
  193. // 这里可能会throw exception
  194. jsonObj = JSON.parse(source);
  195. } catch (ex) {
  196. // new Function的方式,能自动给key补全双引号,但是不支持bigint,所以是下下策,放在try-catch里搞
  197. try {
  198. jsonObj = new Function("return " + source)();
  199. } catch (exx) {
  200. try {
  201. // 再给你一次机会,是不是下面这种情况: "{\"ret\":\"0\", \"msg\":\"ok\"}"
  202. jsonObj = new Function("return '" + source + "'")();
  203. if (typeof jsonObj === 'string') {
  204. // 最后给你一次机会,是个字符串,老夫给你再转一次
  205. jsonObj = new Function("return " + jsonObj)();
  206. }
  207. } catch (exxx) {
  208. this.errorMsgForJson = exxx.message;
  209. }
  210. }
  211. }
  212. // 是json格式,可以进行JSON自动格式化
  213. if (jsonObj != null && typeof jsonObj === "object" && !this.errorMsgForJson.length) {
  214. try {
  215. // 要尽量保证格式化的东西一定是一个json,所以需要把内容进行JSON.stringify处理
  216. source = JSON.stringify(jsonObj);
  217. } catch (ex) {
  218. // 通过JSON反解不出来的,一定有问题
  219. this.errorMsgForJson = ex.message;
  220. }
  221. if (!this.errorMsgForJson.length) {
  222. this.originalJsonStr = source;
  223. // 获取上次记录的排序方式
  224. let curSortType = parseInt(localStorage.getItem(JSON_SORT_TYPE_KEY) || 0);
  225. this.didFormat(curSortType);
  226. // 排序选项初始化
  227. $('[name=jsonsort][value=' + curSortType + ']').attr('checked', 1);
  228. let that = this;
  229. $('[name=jsonsort]').click(function (e) {
  230. let sortType = parseInt(this.value);
  231. if (sortType !== curSortType) {
  232. that.didFormat(sortType);
  233. curSortType = sortType;
  234. }
  235. localStorage.setItem(JSON_SORT_TYPE_KEY, sortType);
  236. });
  237. }
  238. }
  239. // 不是json,都格式化不了,一定会出错
  240. if (this.errorMsgForJson) {
  241. let el = document.querySelector('#optionBar');
  242. el && (el.style.display = 'none');
  243. }
  244. },
  245. didFormat: function (sortType) {
  246. sortType = sortType || 0;
  247. let source = this.originalJsonStr;
  248. if (sortType !== 0) {
  249. let jsonObj = JsonABC.sortObj(JSON.parse(this.originalJsonStr), parseInt(sortType), true);
  250. source = JSON.stringify(jsonObj);
  251. }
  252. Formatter.format(source);
  253. $('.x-toolbar').fadeIn(500);
  254. // 如果是JSONP格式的,需要把方法名也显示出来
  255. if (this.funcName) {
  256. $('#jfCallbackName_start').html(this.funcName + '(');
  257. $('#jfCallbackName_end').html(')');
  258. } else {
  259. this.jfCallbackName_start = '';
  260. this.jfCallbackName_end = '';
  261. }
  262. },
  263. setDemo: function (type) {
  264. if (type === 1) {
  265. this.urlContent = 'http://t.weather.sojson.com/api/weather/city/101030100';
  266. this.methodContent = 'GET';
  267. } else {
  268. this.urlContent = 'https://chrome.fehelper.com/test/post';
  269. this.methodContent = 'POST';
  270. this.paramContent = 'username=postman&password=123456'
  271. }
  272. },
  273. urlParams2String: function (params) {
  274. return params.map((param) => `${param.key}=${param.value}`).join("&")
  275. },
  276. openDonateModal: function(event) {
  277. event.preventDefault();
  278. event.stopPropagation();
  279. chrome.runtime.sendMessage({
  280. type: 'fh-dynamic-any-thing',
  281. thing: 'open-donate-modal',
  282. params: { toolName: 'postman' }
  283. });
  284. },
  285. openOptionsPage: function(event) {
  286. event.preventDefault();
  287. event.stopPropagation();
  288. chrome.runtime.openOptionsPage();
  289. }
  290. }
  291. });