0


09_Vue前端执行后端传递过来的JS代码块

09_Vue前端执行后端传递过来的JS代码块

一、前言

在 Vue 中执行后端传递过来的 JS 代码块可以使用 new Function() 构造函数,但是这样做存在安全风险,因为这允许执行任意代码。在实际应用中,你应该避免直接执行未知或不受信任的代码,因为这可能导致 XSS 攻击或其他安全问题。然而,如果你确信后端提供的代码是安全的并且在工作中确实有这样的需求,你可以按照以下方式执行它。

二、需求

付款时需要生成凭证,后端会处理一部分逻辑,前端需要根据 后端提供的JS代码 去执行,然后将返回结果以接口传参的形式 传递给后端。例如,如果列表页当前行的数据中 ‘是否职能部门’ (isFunction) 这个字段为 ture 的时候,则 ‘摘要’(abstractInfo)的值应该为 ‘科目编码’ + ’ / ’ +‘科目名称’ ,如果这个字段为 false 的时候 ,则 ‘摘要’ ()的值 应该为 ‘科目编码’ + ’ / ’ +‘科目名称’ + ’ / ’ +‘方向’ , 如下 JS

//JS 代码块的 内容if(codeBlockItem.isFunction ===true){
        codeBlockItem.abstractInfo = codeBlockItem.subjectCode +"/"+ codeBlockItem.subjectName
      }elseif(item.isFunction ===false){
        codeBlockItem.abstractInfo = codeBlockItem.subjectCode +"/"+ codeBlockItem.subjectName +"/"+ codeBlockItem.borrowDirect
      }

因为需求 是需要 前端 定义 JS代码块 通过接口 传递给后端,由后端存储到数据库中,在之后的流程,通过接口获取 JS 代码块,在前端执行,执行结果再传递后端 。 实现 JS 代码块可自定义的功能。 所以我们需要 搭建 输入 JS 代码块 的输入框。

三、实操步骤

1、前端生成 JS 代码块

1.1、创建子组件 publicZYPZ

<template><div><el-dialogref="publicZYPZ":title="dialogTitle"class="dDetails":visible.sync="dialogDetails"width="50%":before-close="handleDetailsClose"><divstyle="height: 600px;"><el-buttonsize="mini"type="primary"style="margin-bottom: 10px;"@click="submit">保存</el-button><!-- 输入 JS 代码块 --><el-inputtype="textarea"v-model="jsDmk"></el-input></div></el-dialog></div></template>

并修改其默认样式修改为自己想要的如下 css

/deep/ .el-textarea__inner{height: 550px !important;//设置默认高度
  max-height: 550px !important; //设置最大高度
}

在这里插入图片描述

2、父子组件通信

2.1、 引入自定义组件

import publicZYPZ from'@/views/xxx/dialog/publicZYPZ.vue';//局部注册exportdefault{components:{
        publicZYPZ,},}

2.2、 在页面中使用子组件

<template><div><!--@chang-jsDmk="changjsCode" 将子组件 通过保存按钮得到的数据 传递给父组件 表格中的 ‘摘要’ 字段--><publicZYPZref="publicZYPZ"@chang-jsDmk="changjsCode"/></div></template>

2.3、 父组件 页面如下

<template><divv-show="tableDataShow"style="width: 83.5%;margin-left: .625rem;"><divstyle="margin-bottom: .625rem;text-align: left;"><el-buttonsize="mini"type="success"icon="el-icon-plus"@click="addOne"></el-button><el-buttonsize="mini"type="primary":disabled="isSubmitted":icon="submitIcon"@click="submit">提交</el-button></div><el-table:data="tableDataRight"borderstyle="width: 100%;"max-height="620px"><el-table-columntype="index"label="序号"width="50"align="center"show-overflow-tooltip/><el-table-columnlabel="科目编码"width="170px"align="center"prop="subjectCode"show-overflow-tooltip><template#default="{ row }"><el-input-group><el-input:disabled="inputDisabled"v-model="row.subjectCode"size="small"><template#append><el-buttonsize="mini"style="background-color: #66B1FF;color: white;"type="primary"@click="selectsubjectCode(row)">查看</el-button></template></el-input></el-input-group></template></el-table-column><el-table-columnlabel="科目名称"width="170px"align="center"prop="subjectName"show-overflow-tooltip><template#default="{ row }"><el-tooltipclass="item"effect="dark":content="row.subjectName"placement="top-start"><el-input:disabled="inputDisabled"v-model="row.subjectName"size="small"></el-input></el-tooltip></template></el-table-column><el-table-columnlabel="方向"width="120px"align="center"prop="borrowDirect"show-overflow-tooltip><template#default="{ row }"><el-selectv-model="row.borrowDirect"size="small"placeholder="请选择"><el-optionv-for="item in borrowDirectOptions":key="item.value":label="item.label":value="item.value"></el-option></el-select></template></el-table-column><el-table-columnlabel="辅助核算"width="120px"align="center"prop="accountTypeName"show-overflow-tooltip><template#default="{ row }"><el-selectv-model="row.accountTypeName"size="small"placeholder="请辅助"><el-optionv-for="item in accountTypeNameOptions":key="item.value":label="item.label":value="item.value"></el-option></el-select></template></el-table-column><el-table-columnlabel="是否职能部门"width="120px"align="center"prop="isFunction"show-overflow-tooltip><template#default="{ row }"><el-selectv-model="row.isFunction"size="small"placeholder="请选择"><el-optionv-for="item in isFunctionOptions":key="item.value":label="item.label":value="item.value"></el-option></el-select></template></el-table-column><el-table-columnlabel="行号"width="100px"align="center"prop="inid"show-overflow-tooltip><template#default="{ row }"><el-inputv-model="row.inid"size="small"></el-input></template></el-table-column><el-table-columnlabel="供应商编码"width="150px"align="center"prop="supplierCode"show-overflow-tooltip><template#default="{ row }"><el-inputv-model="row.supplierCode"size="small"></el-input></template></el-table-column><el-table-columnlabel="摘要"width="150px"align="center"prop="abstractInfo"show-overflow-tooltip><template#default="{ row }"><el-input-group><el-inputplaceholder="${key}/${key1}":disabled="inputDisabled"v-model="row.abstractInfo"size="small"><!--点击配置 时调用子组件 --><template#append><el-buttonsize="mini"style="background-color: #66B1FF;color: white;"type="primary"@click="seePz(row)">配置</el-button></template></el-input></el-input-group></template></el-table-column><el-table-columnlabel="借贷计算"width="150px"align="center"prop="formula"show-overflow-tooltip><template#default="{ row }"><el-inputplaceholder="${key}/${key1}"v-model="row.formula"size="small"></el-input></template></el-table-column><el-table-columnlabel="备注"width="200px"align="center"prop="remarks"show-overflow-tooltip><template#default="{ row }"><el-inputv-model="row.remarks"size="small"></el-input></template></el-table-column></el-table></div></template>

并在 methods 中写 调用子组件的 函数

data(){return{JShangRow:undefined,}}methods:{seePz(row){this.JShangRow = row
      const title ='摘要配置JS代码块'//传递 弹窗的标题 和 当前行 的 存放 JS 代码的参数this.$refs["publicZYPZ"].open(title, row.abstractInfo);},}

在这里插入图片描述

2.4、在子组件中编写逻辑,保存时传给父组件

methods:{//接收参数open(title, params){this.dialogDetails =truethis.dialogTitle = title
      //创建一个代码块模板 constcodeBanks=function(){if(codeBlockItem.isFunction ===true){
            codeBlockItem.abstractInfo = codeBlockItem.subjectCode +"/"+ codeBlockItem.subjectName
          }elseif(item.isFunction ===false){
            codeBlockItem.abstractInfo = codeBlockItem.subjectCode +"/"+ codeBlockItem.subjectName +"/"+ codeBlockItem.borrowDirect
          }//将创建的 JS 代码块 交给vue 实例管理this.jsDmk = codeBanks
      }},submit(){this.dialogDetails =false// 传递给父组件 根据父组件中的逻辑 赋值给当前行的 摘要 (abstractInfo )this.$emit('chang-jsDmk',this.jsDmk)},handleDetailsClose(){this.dialogDetails =false},}

2.5、父组件接收传递过来的JS 代码块 ,返给后端

methods:{//1、将数据 给到 表格中的 abstractInfo changjsCode(jsCodeBlock){this.JShangRow.abstractInfo = jsCodeBlock
   },// 2、在提交的时候 将 数据提交给后端 

3、运行JS代码块

3.1、获取后端返回的 JS代码块,并运行

在 Vue 中执行后端传递过来的 JS 代码块可以使用 new Function() 构造函数,

// 假设 sysVitem.abstractInfo 包含从后端接收到的 JS 代码字符串
const codeBlock = sysVitem.abstractInfo;
// 创建一个新的 Function 对象
const func = new Function(‘codeBlockItem’, codeBlock);
// 将 sysVitem 作为参数传递给函数并执行
try {
func(sysVitem);
} catch (error) {
console.error(‘Error executing the code block:’, error);
}
// 注意: 如果 codeBlock 中引用了外部变量或函数,你需要确保这些变量或函数在全局作用域中是可访问的。

methods:{asyncscpz(){//1、传参 发请求 拿需要的详情 和 JS代码块 const params =this.multipleSelection.map(item=>({id: item.id,relatedId: item.relatedId,orgId: item.orgId,relatedType: item.relatedType,voucherFlag: item.voucherFlag,}));if(params.length ==0){this.$message.warning('请选择需要生成凭证的数据');}else{const res =awaitjudgmentAndConfiguration(params)if(res.code ==200){if(res.data.length ==0){this.$message.error('返回data数据为空 无法拿到详情,和JS代码块');}else{// 查询费用详情数据  并拿 JS代码块
            res.data.forEach(item=>{const params ={id: item.relatedId,relatedType: item.relatedType
              }//2、 查询费用详情并调取运行JS代码块的函数this.selectAll(params, item)});this.$message({message: res.msg,type:'success',duration:5000});this.select()}}else{this.$message({message: res.msg,type:'error',duration:5000});}}},// 查费用详情asyncselectAll(params, item){const ress =awaitgetCostRelatedBankPageById(params)//3、运行JS代码块this.runJS(ress.data, item)},// 4、跑JS代码runJS(detailsInfo, item){
      item.sysVoucherConfigureSubList.forEach(sysVitem=>{// 执行 JS 代码块的逻辑try{const codeBlock = sysVitem.abstractInfo
          const func =newFunction('codeBlockItem', codeBlock);// 执行函数func(sysVitem);}catch(error){this.$message({message:'JS代码块不正确,请重新配置',type:'error',duration:5000});}//5、执行完毕 将后端所需要的参数 传递过去const params =[{'voucherConfigureResponse': item,'cdigest': sysVitem.abstractInfo
        }]this.JSvoucherInfoAndInster(params)})},}

在这里插入图片描述

四、总结

这部分需求并不是很难,在实际开发中,我自认为需要考虑的有两点
1、需要效验 后端返回的JS代码块 是否符合自己的逻辑,以及 通过接口拿到的数据,是否包含 JS 代码块中的参数
如果你们有更高的方式 欢迎分享一起讨论。
2、也是最重要的一点,将实际的参数 与JS代码块中用到的参数 对应。

注:不建议把逻辑处理放在前端执行!
存在安全风险,因为这允许执行任意代码。在实际应用中,你应该避免直接执行未知或不受信任的代码,因为这可能导致 XSS 攻击或其他安全问题


本文转载自: https://blog.csdn.net/2302_77229739/article/details/140549526
版权归原作者 一只嘉祺 所有, 如有侵权,请联系我们删除。

“09_Vue前端执行后端传递过来的JS代码块”的评论:

还没有评论