ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

jQuery Ajax 调用 Aspx.Net WebService 实战:用 TaoToken 统一 Key 打通前后端配置

jQuery Ajax 调用 Aspx.Net WebService 实战:用 TaoToken 统一 Key 打通前后端配置 1. 为什么 jQuery Ajax 调 Aspx.Net WebService 总在联调时翻车jQuery Ajax 调用 Aspx.Net WebService是很多老项目里最常见的前后端交互方式前端用$.ajax发 POST后端.asmx暴露[WebMethod]返回 JSON 或 XML。它适合谁适合维护 ASP.NET WebForms 老系统、又不想大改架构的开发者。能做什么一句话让 aspx 页面在不刷新的情况下拿到服务端数据。但真正上手你会发现坑几乎都集中在三处第一contentType写成application/x-www-form-urlencoded服务端直接报 500第二data传了对象而不是 JSON 字符串参数全变 null第三跨域或同域路径写错Network 面板里请求红成一片。更麻烦的是当项目里同时存在多个服务、多个 Key、多个环境时配置散落在web.config、前端 JS、后端代码里联调一次要改五六个地方。这篇就按「aspx 页面发起调用 → WebService 返回 JSON → 浏览器 Network 验证」的完整链路走一遍同时把 TaoToken 的统一 Key 配置骨架嵌进去让前后端配置收敛到一处。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 需要拿 Key 时从那里进控制台即可。2. TaoToken 前置统一 Key 在 WebService 链路里放哪先说清楚定位TaoToken 在这里扮演的是「统一凭证与调用入口」的角色不是替代你的 WebService也不是替代 jQuery。你的.asmx还是那个.asmxjQuery 还是那个 jQuery只是把原来散落的 Key、BaseURL、模型/服务标识收敛成一份配置前端和后端读同一套。对 Aspx.Net 项目来说最自然的落点是web.config的appSettings。这样后端WebService1.asmx.cs里可以用ConfigurationManager.AppSettings[TaoTokenApiKey]读到前端 aspx 页面则通过一个轻量接口把「非敏感配置」吐给 JS敏感 Key 永远不进浏览器。需要提前准备的东西一个 TaoToken 账号从控制台生成 API Key地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content项目里能改web.config的权限jQuery 已引入本地jquery.js或 CDN 都行浏览器能开 DevTools 的 Network 面板注意API Key 属于敏感信息只放在服务端web.config绝对不要硬编码进ws.aspx的script里。前端只拿「是否已配置」「当前环境名」这类无害信息。如果你后面要做长期编码或 Agent 类任务可以顺带看下 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 但本篇的主线仍是 WebService 联调。3. 可复制配置web.config 骨架 aspx 页面 WebService 方法3.1 web.config 里的 WebService 节点与统一 Key在configuration下补appSettings把 TaoToken 的 Key 和 BaseURL 放进去。同时确认system.web里的webServices节点允许脚本调用——这是 Ajax 能打到.asmx的前提。configuration appSettings !-- TaoToken 统一 Key仅服务端读取 -- add keyTaoTokenApiKey valuesk-你的Key / add keyTaoTokenBaseUrl valuehttps://taotoken.net/api / add keyTaoTokenEnv valuedev / /appSettings system.web compilation debugtrue targetFramework4.5 / httpRuntime targetFramework4.5 / webServices protocols add nameHttpPost / add nameHttpGet / /protocols /webServices /system.web /configurationwebServices/protocols这一段是关键。默认情况下.asmx只开 SOAPAjax 用 POST JSON 打过去会被拒。加上HttpPost之后$.ajax的type: POST才能命中方法。3.2 WebService1.asmx.cs加 ScriptService 与 WebMethod后端方法本身不复杂重点是类上必须有[System.Web.Script.Services.ScriptService]否则即使请求打进来也不会走 JSON 序列化。using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Web.Services; namespace jQuery.Learning { [WebService(Namespace http://tempuri.org/)] [WebServiceBinding(ConformsTo WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class WebService1 : System.Web.Services.WebService { [WebMethod] public string HelloWorld() { return Hello World; } [WebMethod] public string GetWish(string value1, string value2, string value3, int value4) { return string.Format(祝您在{3}年里 {0}、{1}、{2}, value1, value2, value3, value4); } [WebMethod] public Listint GetArray(int i) { Listint list new Listint(); while (i 0) { list.Add(i--); } return list; } [WebMethod] public Class1 GetClass() { return new Class1 { ID 1, Value 牛年大吉 }; } [WebMethod] public DataSet GetDataSet() { DataSet ds new DataSet(); DataTable dt new DataTable(); dt.Columns.Add(ID, Type.GetType(System.String)); dt.Columns.Add(Value, Type.GetType(System.String)); DataRow dr dt.NewRow(); dr[ID] 1; dr[Value] 新年快乐; dt.Rows.Add(dr); dr dt.NewRow(); dr[ID] 2; dr[Value] 万事如意; dt.Rows.Add(dr); ds.Tables.Add(dt); return ds; } [WebMethod] public string GetTokenStatus() { // 只回传是否配置不回传 Key 本身 string key ConfigurationManager.AppSettings[TaoTokenApiKey]; string env ConfigurationManager.AppSettings[TaoTokenEnv]; return string.IsNullOrEmpty(key) ? 未配置 : 已配置: env; } } public class Class1 { public string ID { get; set; } public string Value { get; set; } } }GetTokenStatus这个方法就是给前端「探活」用的JS 调它只拿到「已配置:dev」拿不到 Key 明文。3.3 ws.aspx 里的 jQuery Ajax 可复制代码页面结构保持简单重点是$.ajax的四个参数type、contentType、url、data。下面这段可以直接贴进script。$(document).ready(function () { // 无参数调用 $(#btn1).click(function () { $.ajax({ type: POST, contentType: application/json, url: WebService1.asmx/HelloWorld, data: {}, dataType: json, success: function (result) { $(#dictionary).append(result.d); }, error: function (xhr, status, err) { console.error(HelloWorld 失败, status, err, xhr.responseText); } }); }); // 有参数调用 $(#btn2).click(function () { $.ajax({ type: POST, contentType: application/json, url: WebService1.asmx/GetWish, data: JSON.stringify({ value1: 心想事成, value2: 万事如意, value3: 牛牛牛, value4: 2009 }), dataType: json, success: function (result) { $(#dictionary).append(result.d); } }); }); // 返回集合 $(#btn3).click(function () { $.ajax({ type: POST, contentType: application/json, url: WebService1.asmx/GetArray, data: JSON.stringify({ i: 10 }), dataType: json, success: function (result) { $(result.d).each(function () { $(#dictionary).append(this.toString() ); }); } }); }); // 返回复合类型 $(#btn4).click(function () { $.ajax({ type: POST, contentType: application/json, url: WebService1.asmx/GetClass, data: {}, dataType: json, success: function (result) { $(result.d).each(function () { $(#dictionary).append(this[ID] this[Value]); }); } }); }); // 返回 DataSetXML $(#btn5).click(function () { $.ajax({ type: POST, url: WebService1.asmx/GetDataSet, data: {}, dataType: xml, success: function (result) { try { $(result).find(Table1).each(function () { $(#dictionary).append($(this).find(ID).text() $(this).find(Value).text()); }); } catch (e) { alert(e); } }, error: function (result, status) { if (status error) { alert(status); } } }); }); // 探活确认 TaoToken 配置是否生效 $(#btn6).click(function () { $.ajax({ type: POST, contentType: application/json, url: WebService1.asmx/GetTokenStatus, data: {}, dataType: json, success: function (result) { $(#dictionary).append(TaoToken 状态 result.d); } }); }); // 全局 loading 反馈 $(#loading).ajaxStart(function () { $(this).show(); }).ajaxStop(function () { $(this).hide(); }); });这里有个细节值得单独说data参数。老代码里常写data: {value1:心想事成}这种「伪 JSON」在部分 jQuery 版本下能跑但字段名没引号遇到特殊字符就崩。稳妥写法是JSON.stringify({...})让浏览器保证是合法 JSON 字符串。4. 验证请求Network 面板看什么才算成功代码贴完别急着点按钮先开 DevTools 的 Network 面板勾上Preserve log然后点btn1。你要盯的是这几项检查项期望值不对时的含义Request MethodPOST写成 GET 会被 asmx 拒Content-Typeapplication/json写成 form-urlencoded 必 500Status Code200404 是路径错500 是服务端异常Response{d:Hello World}没有d说明没走 JSON 序列化Response HeadersContent-Type: application/json返回 text/xml 说明 ScriptService 没生效点btn2时切到 Payload 标签确认请求体是{value1:心想事成,value2:万事如意,value3:牛牛牛,value4:2009}。如果看到的是value1心想事成value2...说明contentType没设对。点btn6时Response 应该是{d:已配置:dev}。如果返回「未配置」回到web.config检查TaoTokenApiKey的 key 名是否拼错——大小写敏感。提示如果 Network 里请求是红的先看 Console 有没有 CORS 报错。同域调用一般不会触发但如果你把 aspx 和 asmx 部署在不同端口就需要在web.config里加customHeaders或改用同源部署。5. 本篇常见错排查500、null、d 取不到错误一POST 500Response 里带System.InvalidOperationException。九成是contentType不是application/json或者data不是合法 JSON 字符串。检查$.ajax里这两行别用对象直接传。错误二方法能进但参数全是 null。Aspx.Net WebService 对参数名大小写敏感。前端传{Value1:...}后端方法签名是string value1就对不上。统一用小写开头和 C# 参数名保持一致。错误三result.d是 undefined。两种可能一是类上漏了[ScriptService]返回的是 XML 而不是 JSON二是dataType写成了xml却按 JSON 解析。用 Network 的 Response 标签确认实际返回格式。错误四web.config改了不生效。IIS 会缓存配置改完web.config后回收一下应用程序池或者直接iisreset。另外确认webServices节点没被上层machine.config覆盖。错误五跨域时预检请求 OPTIONS 返回 405。.asmx默认不处理 OPTIONS。同域部署最省事确实要跨域在web.config的system.webServer里加httpProtocol/customHeaders配 CORS 头并确保 OPTIONS 不被拦。错误六Key 读出来是空字符串。ConfigurationManager.AppSettings读的是web.config的appSettings不是connectionStrings。key 名要和代码里完全一致包括大小写。6. 把 Key 收敛之后下一步怎么走联调一次通过的关键其实不在 jQuery 写得多花而在配置有没有收敛。web.config里一份appSettings后端ConfigurationManager读前端只通过GetTokenStatus探活Key 永远不出服务端——这条链路跑通之后换环境、换 Key、加服务都只动一个文件。如果你要验证模型对话相关的调用可以从模型对话入口进https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 要管理 Key 和查看用量走控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。API 基址统一用 https://taotoken.net/api 不要加多余参数。最后留一个我踩过的坑GetDataSet返回 XML 时dataType必须是xml而且$(result).find(Table1)里的表名要和 DataTable 默认名一致。如果你给 DataTable 起了别名find 的字符串也要跟着改否则循环体一次都不进页面看着「没报错但没数据」最难查。
返回列表