# MESCommonBase 响应输出与 SqlWebCall 默认分支详细文档 文档范围:流程图中下半部分的两块内容。 - `响应输出` - `DataLink.SqlWebCall 默认分支` 关联入口:`MES_Manage/submit/MESCommonBase.ashx` 生成时间:2026-07-02 ## 1. 相关程序清单 | 程序文件 | 关键位置 | 作用 | | --- | --- | --- | | `MES_Manage/submit/MESCommonBase.ashx` | `ProcessRequest` 的 `switch(type)` 和外层 `catch` | 负责把不同 Type 的结果写入 HTTP 响应 | | `02DataLinkMesWork/DataLinkMesWork.SqlWebCall.cs` | `DataLink.SqlWebCall(int type, JsonData jsonData, jsonobj dataobj)` | 默认分支二次分发入口 | | `02DataLinkMesWork/DataLinkMesWork.SqlWebCall.cs` | `InitSystemReg(...)` | 初始化数据库连接字符串 | | `02DataLinkMesWork/DataLinkMesWork.SqlWebCall.cs` | `GetString_JsonData(...)` | 从新协议 JSON 读取 `Type/Name/Param/token` 等字段 | | `02DataLinkMesWork/DataLinkMesWork.cs` | `ExePROCEDURE_Type*`、`ExecuteInsertMesWork`、`ExecuteSelectMesWork` | 具体 SQL、存储过程、登录、分页、返回格式处理 | | `02DataLinkMesWork/P0.MES.Common/bizDataAccess/SQLCommon.cs` | `ExecuteStoredProcedure`、`ExecuteDataTable`、`ExecuteDataset`、`ExecuteInsertMesWork`、`ExecuteSelectMesWork` | 底层 ADO.NET 数据库执行封装 | | `01BasicData/BasicData/BasicData.cs` | `jsonobj` | 旧协议请求对象 | | `MES_Manage/Web.config` | `appSettings["ConnectionString"]` | 默认数据库连接配置来源 | ## 2. 这部分在总流程中的位置 `MESCommonBase.ashx` 先解析请求体或 `param` 参数,拿到 `type` 后进入 `switch(type)`。 流程图下半部分对应的是: ```text switch(type) | |-- 文件下载分支 2001/2002/2003/2004/16 -> 响应输出:二进制下载 |-- 文件上传分支 15 -> 响应输出:JSON 文本 |-- IP 查询分支 4000 -> 响应输出:文本 IP |-- default -> DataLink.SqlWebCall(...) -> 响应输出:JSON 文本 ``` 也就是说,`响应输出` 是所有分支最终面向 HTTP 客户端的出口;`DataLink.SqlWebCall 默认分支` 是普通业务请求的二次路由器。 ## 3. 响应输出:程序流程 ### 3.1 默认响应头 `ProcessRequest` 进入后先执行: ```csharp context.Response.ContentType = "application/json"; ``` 因此除文件下载分支外,默认都会以 `application/json` 作为响应类型。需要注意:`Type=4000` 实际写出的是纯文本 IP,但 Content-Type 没有改成 `text/plain`。 ### 3.2 二进制下载响应 适用 Type: - `2001` - `2002` - `2003` - `2004` - `16` 典型代码模式: ```csharp HttpContext.Current.Response.ContentType = "application/octet-stream"; HttpContext.Current.Response.AddHeader( "Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName, Encoding.UTF8) ); HttpContext.Current.Response.AddHeader( "Access-Control-Expose-Headers", "Content-Disposition" ); HttpContext.Current.Response.BinaryWrite(bytes); HttpContext.Current.Response.Flush(); HttpContext.Current.Response.End(); ``` 字段含义: | 字段 | 含义 | | --- | --- | | `ContentType = application/octet-stream` | 告诉浏览器按二进制文件处理 | | `Content-Disposition = attachment` | 触发浏览器下载,而不是直接打开 | | `filename=...` | 下载文件名,使用 UTF-8 URL 编码处理中文文件名 | | `Access-Control-Expose-Headers` | 允许跨域前端读取 `Content-Disposition` 响应头 | | `BinaryWrite(bytes)` | 写出文件二进制 | | `Flush()` | 刷新响应缓冲区 | | `End()` / `Close()` | 结束响应 | 不同文件分支的差异: | Type | 生成文件的程序 | 文件名来源 | 结束方式 | | --- | --- | --- | --- | | `2001` | `ExcelWebCall.ExcelFile(...)` | `fileName + "." + fileExtension` | `Response.End()` | | `2002` | `ExcelWebCall.ExcelFilePdf(...)` | `fileName + "." + fileExtension`,通常为 PDF | `Response.End()` | | `2003` | `ExcelWebCall.ExcelFile(...)` | `fileName + "." + dataimg[0]` | `Response.Close()` | | `2004` | `DataLink.ExePROCEDURE_Type2004(...)` | 数据库返回文件名和扩展名 | `Response.End()` | | `16` | `DataLink.ExePROCEDURE_Type16(...)` | 数据库返回文件名和后缀 | `Response.End()` | ### 3.3 Type=16 的空文件处理 `Type=16` 下载前有一层空判断: ```csharp DataLink.ExePROCEDURE_Type16(jsonData, out bytes, out fileName, out suffix); if (bytes == null) return; ``` 如果下游没有返回文件二进制,则直接 `return`,不会写 JSON 错误,也不会写文件响应。调用方看到的可能是空响应。 ### 3.4 Type=15 上传文件后的 JSON 响应 `Type=15` 是上传文件分支,不返回下载流。 流程: ```text 读取 context.Request.Files | |-- 有文件: | 读取第一个文件 InputStream 为 byte[] | 从 FileName 拆 name/suffix | 调 DataLink.ExePROCEDURE_Type15(jsonData, name, suffix, bytes) | Response.Write(responseText) | |-- 无文件: name="" suffix="" bytes=new byte[1] 调同一个 ExePROCEDURE_Type15 Response.Write(responseText) ``` `responseText` 来自下游存储过程调用,常见返回: ```json [{"result":"1"}] ``` 或: ```json [{"result":"0"}] ``` ### 3.5 Type=4000 的文本响应 `Type=4000` 返回请求 IP: ```csharp context.Response.Write(userIP); ``` 当前 IP 判断逻辑: ```csharp if (context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != "") userIP = context.Request.ServerVariables["REMOTE_ADDR"]; else userIP = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (userIP == null || userIP == "") userIP = context.Request.UserHostAddress; ``` 注意:这里逻辑疑似写反。通常 `HTTP_X_FORWARDED_FOR` 有值时才优先取它;当前代码在有转发头时反而取 `REMOTE_ADDR`。 ### 3.6 default 分支的 JSON 响应 普通业务请求进入 default: ```csharp responseText = DataLinkMesWork.DataLink.SqlWebCall(type, jsonData, dataobj); context.Response.Headers.Remove("Server"); context.Response.Write(responseText); ``` 特点: - 响应体完全由 `SqlWebCall` 返回值决定。 - 尝试移除 `Server` 响应头。 - 仍使用入口处默认的 `application/json`。 - `SqlWebCall` 对未支持 Type 返回空字符串。 ### 3.7 外层异常响应 `ProcessRequest` 外层包了一个总 `try/catch`: ```csharp string responseText = "NULL"; try { ... } catch(Exception err) { context.Response.Write(responseText); } ``` 异常后的响应行为: - 不记录异常。 - 不设置 HTTP 状态码。 - 写出当前 `responseText`。 - 如果异常发生在下游调用前,返回 `"NULL"`。 - 如果异常发生在 `responseText` 已赋值之后,可能返回旧结果。 ## 4. DataLink.SqlWebCall 默认分支:入口流程 入口签名: ```csharp public static string SqlWebCall(int type, JsonData jsonData, jsonobj dataobj) ``` 调用来源: ```csharp DataLinkMesWork.DataLink.SqlWebCall(type, jsonData, dataobj) ``` 调用时机:`MESCommonBase.ashx` 的 `switch(type)` 没有匹配到 `2001/2002/2003/2004/15/16/4000` 时进入。 ### 4.1 初始化数据库连接 `SqlWebCall` 开始时检查静态字段 `initSystemIsOk`: ```csharp if (!initSystemIsOk) { if (!InitSystemReg(out resultReg)) { return resultReg; } } ``` `InitSystemReg` 当前实际逻辑: ```csharp connectionString = ConfigurationManager.AppSettings["ConnectionString"]; initSystemIsOk = true; return true; ``` 说明: - 第一次进入 `SqlWebCall` 时,从 `Web.config` 读取 `ConnectionString`。 - 成功后设置静态标记,后续调用复用。 - 原先注册号、序列号、加密连接串等校验逻辑已经被注释。 ### 4.2 二次分发 初始化后进入 `switch(type)`: ```text SqlWebCall(type,jsonData,dataobj) | |-- 8888 / 5001 / 5002:加密、注册/改密、登录 |-- 1 / 2 / 5:旧协议存储过程 |-- 11 / 111 / 12 / 13 / 21:新协议存储过程 |-- 1001 / 1002 / 3 / 4 / 7 / 22 / 3001:SQL、建表导入、SQL 命令 ``` `SqlWebCall` 自身不直接访问数据库;它只选择具体方法。真正数据库执行在: - `DataLinkMesWork.cs` - `SQLCommon.cs` ## 5. SqlWebCall 支持的 Type 明细 ### 5.1 登录、注册、加密类 | Type | 方法 | 输入对象 | 主要流程 | 返回 | | --- | --- | --- | --- | --- | | `8888` | `GetEncryptStr(jsonData)` | 新协议 `JsonData` | 读取 `Name/name`,用 `AesKeyIvGenerator.Encrypt(name1, SN, SN)` 加密 | 加密字符串,失败默认 `[]` | | `5001` | `ExePROCEDURE_Type11_AddUser(jsonData)` | 新协议 `JsonData` | 读取 `Param` 数组,找到 `Password` 后 MD5,再执行 `Name` 指定存储过程 | 存储过程首表 JSON 或 `[]` | | `5002` | `ExePROCEDURE_Type11_Login(jsonData)` | 新协议 `JsonData` | 解密前端密码,执行 `Name` 指定存储过程查账号,再比对数据库密码,成功后写入 token | 成功返回用户表 JSON 并追加 `token`,失败返回 `result=0,msg=...` | 登录成功后会调用固定存储过程: ```text 权限管理_Token_增加数据 ``` 校验 token 时调用: ```text 权限管理_Token_查询数据 ``` ### 5.2 旧协议存储过程类 旧协议使用 `BasicData.jsonobj dataobj`,字段为: ```csharp public string Type; public string ModularID; public string Name; public string Param; public string UserID; public string Pagination; public string token; public bool HasReturn; ``` | Type | 方法 | 执行对象 | 参数格式 | 返回 | | --- | --- | --- | --- | --- | | `1` | `ExePROCEDURE_Type1(dataobj)` | `Name` 的第一个 `&` 前作为存储过程名 | `@p=value=type&@p2=value=type` | 首个 DataTable JSON;分页时返回带总数结构;失败 `result=0` | | `2` | `ExePROCEDURE_Type2(dataobj)` | `Name` 指定存储过程 | 同 Type 1 | 成功 `result=1`,失败 `result=0` | | `5` | `ExePROCEDURE_Type5(dataobj)` | `Name` 指定存储过程 | `@p&value&type|@p2&value&type` | 首个 DataTable JSON;参数错误返回中文错误字符串 | 旧协议参数解析在 `SQLCommon.GetCmdParam(...)` 中完成: ```text 多个参数:用 & 分隔 单个参数:参数名=值=类型 输出参数:参数名=值=类型=output ``` 支持类型: - `int` - `string` - `boolean` - `datetime` - 默认按字符串处理 token 行为: - `Type=1/2/3/4/5` 都是“如果 token 非空则校验”。 - 不传 token 时通常不会拒绝执行。 ### 5.3 新协议存储过程类 新协议使用 `JsonData jsonData`,字段从请求 JSON 中读取: ```json { "type": "11", "name": "存储过程名", "param": "[{\"name\":\"@p\",\"value\":\"v\",\"type\":\"string\"}]", "token": "..." } ``` 通用字段读取由 `GetString_JsonData(...)` 完成,兼容大小写: | 大写字段 | 小写字段 | 含义 | | --- | --- | --- | | `Type` | `type` | Type | | `Name` | `name` | 存储过程名或 SQL 文本 | | `Param` | `param` | 参数数组字符串 | | `UserID` | `userID` | 用户 | | `Pagination` | `pagination` | 旧分页参数 | | `HasReturn` | `hasReturn` | 是否返回 | | `ModularID` | `modularID` | 模块 | | `token` | `token` | token | #### Type=11:查询型存储过程 方法: ```csharp ExePROCEDURE_Type11(jsonData) ``` 流程: ```text 读取 Name/Param/token | |-- token 非空:CheckToken(token),失败返回 [{"result":"3"}] | |-- Param 为空:无参数执行存储过程 |-- Param 非空:解析 JSON 数组为 SqlParameter[] | |-- SQLCommon.ExecuteStoredProcedure(... out DataSet ...) | |-- 有结果表: |-- 有 pageSize/pageList:内存分页,返回分页 JSON |-- 无分页字段:返回首个 DataTable JSON | |-- 有 output 参数:包装为 {"result":..., "output":...} ``` #### Type=111:服务端分页存储过程 方法: ```csharp ExePROCEDURE_Type111(jsonData) ``` 它解决“通讯服务器分页”的问题。 如果请求中包含: ```json { "pageSize": 20, "pageList": 1 } ``` 程序会自动向参数数组追加 4 个参数: | 参数名 | 值 | 说明 | | --- | --- | --- | | `PageCurrent` | `pageList` | 当前页 | | `PageSize` | `pageSize` | 每页条数 | | `PageCount` | `1111`,`type=int`,`output=1` | 输出参数 | | `ItemCount` | `1111`,`type=int`,`output=1` | 输出参数,总记录数 | 执行后返回: ```json { "rows": [], "total": "总记录数" } ``` 其中 `total` 来自输出参数 `ItemCount`。 #### Type=12:执行型存储过程 方法: ```csharp ExePROCEDURE_Type12(jsonData) ``` 特点: - 执行 `Name/name` 指定存储过程。 - 不关注 DataSet。 - 成功返回: ```json [{"result":"1"}] ``` - 失败返回: ```json [{"result":"0"}] ``` - 如果有输出参数,返回: ```json { "result": [{"result":"1"}], "output": [{"参数名":"参数值"}] } ``` #### Type=13:返回 DataSet JSON 方法: ```csharp ExePROCEDURE_Type13(jsonData) ``` 特点: - 执行 `Name/name` 指定存储过程。 - 返回整个 `DataSet` 的 JSON,而不是只返回第一张表。 - 有输出参数时包装为: ```json { "result": { "DataSet序列化结果": "..." }, "output": [{"参数名":"参数值"}] } ``` #### Type=21:新响应结构的存储过程 方法: ```csharp ExePROCEDURE_Type21(jsonData) ``` 特点: - 仍然执行 `Name/name` 指定存储过程。 - 返回结构改为: ```json { "code": "200", "message": "", "data": {} } ``` 或: ```json { "code": "500", "message": "错误信息", "data": {} } ``` 注意:这里是否成功主要看底层返回的 `result` 字符串是否为空,不完全等同于数据库是否返回数据。 ### 5.4 SQL 文本和建表导入类 | Type | 方法 | 执行对象 | 返回 | | --- | --- | --- | --- | | `1001` | `ExecuteInsertMesWork(jsonData)` | `Name/name` 作为 SQL 文本,参数来自 `Param` JSON 数组 | 成功 `result=1`;有输出时返回 `output` | | `1002` | `ExecuteSelectMesWork(jsonData)` | `Name/name` 作为 SQL 查询文本,参数来自 `Param` JSON 数组 | DataTable JSON;支持 `pageSize/pageList` 内存分页 | | `3` | `ExePROCEDURE_Type3(dataobj)` | `dataobj.Name` 作为 SQL 查询文本 | DataTable JSON | | `4` | `ExePROCEDURE_Type4(dataobj)` | `dataobj.Name` 作为非查询 SQL 文本 | 成功 `result=1` | | `7` | `ExePROCEDURE_Type7(jsonData)` | `Name/name` 作为表名,`Param` 作为行数据 | 删除并重建表,批量插入,成功 `result=1` | | `22` | `ExePROCEDURE_Type22(dataobj)` | `dataobj.Name` 作为 SQL 文本 | `{ code, message, data }` | | `3001` | `DbCallType1003_SqlCmd.SqlExec(jsonData)` | SQL 命令执行入口 | 由该方法决定 | 这类 Type 的共性: - 执行对象来自客户端 `Name/name`。 - 参数虽然使用 `SqlParameter` 绑定,但 SQL 文本或表名本身不是固定白名单。 - 需要调用方和网络边界可信,否则风险很高。 ## 6. SqlWebCall 参数处理流程 ### 6.1 新协议 Param 数组字符串 常见格式: ```json { "type": "11", "name": "存储过程名", "param": "[{\"name\":\"@工位号\",\"value\":\"OP10\",\"type\":\"string\"},{\"name\":\"@数量\",\"value\":\"10\",\"type\":\"int\"}]" } ``` 处理逻辑: ```text param 字符串 | |-- JsonMapper.ToObject(param) | |-- 遍历数组 |-- name:SqlParameter 名 |-- value:参数值;如果是数组,转为逗号字符串并做 Unicode 解码 |-- type:存在时做类型转换 |-- output == "1":改为输出参数 | |-- SQLCommon.ExecuteStoredProcedure / ExecuteSelectMesWork / ExecuteInsertMesWork ``` 支持类型主要为: - `int` - `string` - `boolean` - `bool` - `datetime` - 默认字符串 ### 6.2 旧协议 Param 拼接字符串 Type 1/2 的旧协议格式: ```text @p1=value1=string&@p2=10=int&@out=0=int=output ``` `SQLCommon.GetCmdParam(...)` 处理逻辑: ```text Param | |-- 按 & 分割参数 |-- 过滤包含 == / null / undefined 的项 |-- 每项按 = 分割 |-- 长度 2:直接字符串参数 |-- 长度 3:按类型转换 |-- 长度 4 且第 4 项为 output:设为输出参数 ``` Type 5 的旧协议格式不同: ```text @p1&value1&String|@p2&10&Int ``` ## 7. 底层数据库执行链路 ### 7.1 存储过程查询 典型调用链: ```text MESCommonBase.ashx default -> DataLink.SqlWebCall(...) -> DataLink.ExePROCEDURE_Type11/13/21(...) -> SQLCommon.ExecuteStoredProcedure(...) -> SqlConnection / SqlDataAdapter -> DataSet / DataTable -> JsonHelper / JsonConvert 序列化 -> Response.Write(responseText) ``` `SQLCommon.ExecuteStoredProcedure(... out DataSet ...)` 的关键行为: - 创建 `SqlConnection`。 - 创建 `SqlCommand(procedureName, conn)`。 - 设置 `CommandType = StoredProcedure`。 - 设置 `CommandTimeout = 0`,即不限制命令超时。 - 添加 `SqlParameter[]`。 - 使用 `SqlDataAdapter.Fill(ds)` 填充结果集。 - 异常时写 `ApplicationLog`,并通过 `errorMessage` 返回异常字符串。 ### 7.2 SQL 查询 典型调用链: ```text Type 1002 / 3 / 22 -> SQLCommon.ExecuteSelectMesWork 或 ExecuteDataTable / ExecuteDataset -> SqlDataAdapter(sql, conn) -> Fill(DataTable/DataSet) -> JSON ``` ### 7.3 SQL 增删改 典型调用链: ```text Type 1001 / 4 -> SQLCommon.ExecuteInsertMesWork 或 ExecuteNonQuery -> SqlCommand.CommandText = SQL 文本 -> ExecuteNonQuery / ExecuteScalar -> result=1 或 result=0 ``` ## 8. 返回格式汇总 ### 8.1 成功返回首表 JSON 常见于: - `Type=1` - `Type=3` - `Type=5` - `Type=11` - `Type=1002` 示例: ```json [ { "字段1": "值1", "字段2": "值2" } ] ``` ### 8.2 成功/失败标志 常见于: - `Type=2` - `Type=4` - `Type=12` - `Type=1001` 成功: ```json [{"result":"1"}] ``` 失败: ```json [{"result":"0"}] ``` ### 8.3 token 失败 部分方法在 token 非空且校验失败时返回: ```json [{"result":"3"}] ``` ### 8.4 输出参数包装 普通输出参数: ```json { "result": [{"result":"1"}], "output": [{"@out":"123"}] } ``` 分页输出参数: ```json { "rows": [], "total": "123" } ``` ### 8.5 新结构响应 常见于: - `Type=21` - `Type=22` ```json { "code": "200", "message": "", "data": {} } ``` 失败: ```json { "code": "500", "message": "错误信息", "data": {} } ``` ### 8.6 空或未支持 Type `SqlWebCall` 对未匹配 Type 没有 default 处理,`result` 初始为空字符串。 因此 `MESCommonBase.ashx` default 分支可能返回空响应体: ```text "" ``` 如果进入外层异常,则可能返回: ```text NULL ``` ## 9. 鉴权与 token 逻辑 `CheckToken(token)` 逻辑: ```text token == "" -> true token 非空: 调 权限管理_Token_查询数据 | |-- 存储过程报错 -> false |-- 返回空表 -> false |-- 返回有数据 -> true ``` 关键影响: - 多数业务方法只有在 `token` 非空时才调用 `CheckToken`。 - 如果请求不传 token,常见路径不会拒绝。 - `SqlWebCall` 入口层没有统一鉴权。 - 因此权限控制依赖调用方是否传 token,以及下游存储过程是否自行校验。 ## 10. 风险点与维护注意事项 ### 10.1 响应层风险 1. `Response.End()` 位于大 try 内,可能触发 `ThreadAbortException`,随后外层 catch 写出 `responseText`。 2. 下载失败时没有统一 JSON 错误,`Type=16` 的 `bytes == null` 会直接空返回。 3. `Type=4000` 返回纯文本,但 Content-Type 仍可能是 `application/json`。 4. 外层异常不记录日志,定位问题困难。 5. 多种响应格式混用,前端必须按 Type 分别处理。 ### 10.2 SqlWebCall 风险 1. 客户端可通过 `Name/name` 指定存储过程名、SQL 文本或表名。 2. `Type=3/4/22/1001/1002/3001` 存在直接 SQL 执行能力。 3. `Type=7` 可根据请求表名执行 `DROP TABLE` 和 `CREATE TABLE`。 4. token 校验不是统一强制的。 5. `CommandTimeout = 0` 可能导致长时间阻塞。 6. 失败返回经常只有 `result=0`,缺少错误原因。 ### 10.3 参数层风险 1. 新协议 `Param` 是 JSON 字符串,不是 JSON 对象;调用方需要二次转义。 2. 输出参数类型转换依赖 `type` 和 `output` 字段,格式错误会进入 catch 并返回 `result=0`。 3. 数组参数被拼成逗号字符串,数组元素里如果本身包含逗号,语义会丢失。 4. 旧协议分隔符为 `&`、`=`、`|`,参数值包含这些字符时容易解析错误。 ## 11. 建议改进方案 ### 11.1 低成本修复 - 在 `MESCommonBase.ashx` default 分支前统一校验 token。 - 未支持 Type 返回明确错误: ```json {"code":"400","message":"Unsupported Type","data":null} ``` - 下载分支改为 `HttpContext.Current.ApplicationInstance.CompleteRequest()`,避免 `Response.End()` 的线程中止异常。 - `Type=4000` 设置 `ContentType = "text/plain"`,并修正代理 IP 判断逻辑。 - 外层 catch 记录异常:Type、Name、IP、异常堆栈。 ### 11.2 中期改造 - 建立 `Type + Name` 白名单,禁止任意存储过程名和 SQL 文本。 - 将 `Param` 从“JSON 字符串”改为真正的 JSON 数组字段。 - 统一 JSON 返回结构: ```json { "code": "200", "message": "", "data": {} } ``` - 将 SQL 执行类 Type 与普通业务接口分离。 ### 11.3 长期改造 - 按业务模块拆分接口,减少万能网关。 - 数据库账号按能力拆分权限。 - 移除明文连接字符串,使用部署环境密钥。 - 对文件下载、上传、SQL 执行加入审计日志和限流。 ## 12. 典型流程示例 ### 12.1 Type=11 查询型存储过程 请求: ```json { "type": "11", "name": "MES_工位_查询", "param": "[{\"name\":\"@工位号\",\"value\":\"OP10\",\"type\":\"string\"}]", "token": "token值" } ``` 流程: ```text MESCommonBase.ashx default -> SqlWebCall(11,jsonData,dataobj) -> InitSystemReg 读取连接字符串 -> ExePROCEDURE_Type11 -> GetString_JsonData 读取 name/param/token -> token 非空则 CheckToken -> Param 转 SqlParameter[] -> SQLCommon.ExecuteStoredProcedure -> JsonHelper.DataTableToJson -> Response.Write(JSON) ``` ### 12.2 Type=111 分页型存储过程 请求: ```json { "type": "111", "name": "MES_工位_分页查询", "param": "[{\"name\":\"@关键字\",\"value\":\"OP\",\"type\":\"string\"}]", "pageSize": 20, "pageList": 1 } ``` 内部自动追加分页参数: ```text PageCurrent = 1 PageSize = 20 PageCount = 输出参数 ItemCount = 输出参数 ``` 响应: ```json { "rows": [], "total": "100" } ``` ### 12.3 Type=1002 SQL 查询 请求: ```json { "type": "1002", "name": "select * from Test where f1=@f1", "param": "[{\"name\":\"@f1\",\"value\":\"T002\",\"type\":\"string\"}]" } ``` 流程: ```text SqlWebCall(1002) -> ExecuteSelectMesWork(jsonData) -> SQLCommon.ExecuteSelectMesWork(sql, params, connectionString, out dt) -> DataTableToJson ``` 说明:参数值通过 `SqlParameter` 绑定,但 SQL 文本本身来自请求。 ## 13. 结论 流程图中的 `响应输出` 是整个 `MESCommonBase.ashx` 的 HTTP 出口,负责二进制下载、JSON 文本、IP 文本和异常兜底输出。`DataLink.SqlWebCall 默认分支` 是普通业务请求的二次分发中心,它按 Type 调用不同数据库执行方法,覆盖登录、存储过程、SQL 查询、SQL 增删改、分页和新结构返回。 这部分程序的核心问题不是流程复杂,而是执行权过于通用:客户端可通过 `type + name + param` 控制大量数据库行为。维护时应优先关注统一鉴权、Type/Name 白名单、异常日志和响应格式统一。