AJAX ASP
用 ASP 写 AJAX 接口:返回文本、XML、JSON,处理参数与错误。
返回纯文本
<%
Response.ContentType = "text/plain"
Response.Charset = "UTF-8"
Dim name
name = Request.QueryString("name")
If name = "" Then name = "World"
Response.Write "Hello, " & name
%>const res = await fetch('hello.asp?name=Ada');
document.getElementById('out').textContent = await res.text();Hello, Ada返回 XML
<%
Response.ContentType = "text/xml"
Response.Charset = "UTF-8"
Response.Write "<?xml version=""1.0"" encoding=""utf-8""?>"
Response.Write "<users>"
Do While Not rs.EOF
Response.Write "<user id=""" & rs("id") & """>" & _
Server.HTMLEncode(rs("name")) & "</user>"
rs.MoveNext
Loop
Response.Write "</users>"
%>const res = await fetch('users.asp');
const xml = new DOMParser().parseFromString(await res.text(), 'text/xml');
const names = [...xml.querySelectorAll('user')].map(u => u.textContent);An XML response must start with <?xml ...?> on line one; any leading whitespace (BOM, blank line) makes DOMParser fail. The file cannot begin with a space.
返回 JSON
<%
Response.ContentType = "application/json"
Response.Charset = "UTF-8"
Dim rows, i, first
rows = Array(Array(1, "Ada"), Array(2, "Bob"))
Response.Write "["
For i = 0 To UBound(rows)
If i > 0 Then Response.Write ","
Response.Write "{""id"":" & rows(i)(0) & ",""name"":""" & _
JsonEsc(rows(i)(1)) & """}"
Next
Response.Write "]"
Function JsonEsc(s)
Dim t
t = Replace(s, "\", "\\")
t = Replace(t, """", "\""")
t = Replace(t, vbCr, "\r")
t = Replace(t, vbLf, "\n")
t = Replace(t, vbTab, "\t")
JsonEsc = t
End Function
%>[{"id":1,"name":"Ada"},{"id":2,"name":"Bob"}]The main risk of hand-written JSON is incomplete escaping: miss one of backslash, quote, newline or a control character and JSON.parse fails entirely. Cover at least those five, or bring in a JSON library.
错误处理
<%
Response.ContentType = "application/json"
Response.Charset = "UTF-8"
On Error Resume Next
Dim data
data = DoSomethingRisky()
If Err.Number <> 0 Then
Response.Status = "500 Internal Server Error"
Response.Write "{""ok"":false,""error"":""服务器处理失败""}"
' 细节写日志
Err.Clear
Else
Response.Write "{""ok"":true,""data"":""" & JsonEsc(data) & """}"
End If
On Error GoTo 0
%>Return a non-2xx status on failure. A 200 with {ok:false} never reaches fetch's catch, forcing the frontend to inspect business fields — easy to forget.
防缓存
<%
Response.CacheControl = "no-cache"
Response.Expires = -1
Response.AddHeader "Pragma", "no-cache"
%>// 或者加时间戳,让每次请求的 URL 都不同
fetch(`data.asp?t=${Date.now()}`);IE caches GET requests aggressively, serving the second request from cache without hitting the server. In development this looks like "the backend change had no effect"; no-cache or a timestamp parameter fixes it.
Request in SQL are injection; in returned HTML fragments they are XSS. "Internal call" is not an excuse — anything a browser can request is public.返回纯文本
<%
Response.ContentType = "text/plain"
Response.Charset = "UTF-8"
Dim name
name = Request.QueryString("name")
If name = "" Then name = "World"
Response.Write "Hello, " & name
%>const res = await fetch('hello.asp?name=Ada');
document.getElementById('out').textContent = await res.text();Hello, Ada返回 XML
<%
Response.ContentType = "text/xml"
Response.Charset = "UTF-8"
Response.Write "<?xml version=""1.0"" encoding=""utf-8""?>"
Response.Write "<users>"
Do While Not rs.EOF
Response.Write "<user id=""" & rs("id") & """>" & _
Server.HTMLEncode(rs("name")) & "</user>"
rs.MoveNext
Loop
Response.Write "</users>"
%>const res = await fetch('users.asp');
const xml = new DOMParser().parseFromString(await res.text(), 'text/xml');
const names = [...xml.querySelectorAll('user')].map(u => u.textContent);XML 输出必须第一行就是 <?xml ...?>,前面有任何空白(包括 BOM、空行)都会让 DOMParser 报错。文件开头不能有空格。
返回 JSON
<%
Response.ContentType = "application/json"
Response.Charset = "UTF-8"
Dim rows, i, first
rows = Array(Array(1, "Ada"), Array(2, "Bob"))
Response.Write "["
For i = 0 To UBound(rows)
If i > 0 Then Response.Write ","
Response.Write "{""id"":" & rows(i)(0) & ",""name"":""" & _
JsonEsc(rows(i)(1)) & """}"
Next
Response.Write "]"
Function JsonEsc(s)
Dim t
t = Replace(s, "\", "\\")
t = Replace(t, """", "\""")
t = Replace(t, vbCr, "\r")
t = Replace(t, vbLf, "\n")
t = Replace(t, vbTab, "\t")
JsonEsc = t
End Function
%>[{"id":1,"name":"Ada"},{"id":2,"name":"Bob"}]手写 JSON 最大的风险是转义不全:反斜杠、双引号、换行、控制字符漏一个,前端 JSON.parse 就整个失败。至少把这五个替换写全,或者引入现成的 JSON 库。
错误处理
<%
Response.ContentType = "application/json"
Response.Charset = "UTF-8"
On Error Resume Next
Dim data
data = DoSomethingRisky()
If Err.Number <> 0 Then
Response.Status = "500 Internal Server Error"
Response.Write "{""ok"":false,""error"":""服务器处理失败""}"
' 细节写日志
Err.Clear
Else
Response.Write "{""ok"":true,""data"":""" & JsonEsc(data) & """}"
End If
On Error GoTo 0
%>接口出错时要返回非 2xx 状态码。返回 200 加 {ok:false} 会让 fetch 的 catch 永远不触发,前端只能靠解析业务字段判断成败——容易漏。
防缓存
<%
Response.CacheControl = "no-cache"
Response.Expires = -1
Response.AddHeader "Pragma", "no-cache"
%>// 或者加时间戳,让每次请求的 URL 都不同
fetch(`data.asp?t=${Date.now()}`);IE 对 GET 请求的缓存极其激进,同一个 URL 第二次直接读缓存不发给服务器。开发时表现为「改了后端但页面没变」,加 no-cache 或时间戳参数就能解决。
Request 里的值拼进 SQL 就是注入;拼进返回的 HTML 片段就是 XSS。接口不是「内部调用」就可以放松——浏览器里的任何请求都是公开的。