WebForms页面用Refit调用REST API报错 求示例及解决方案
问题分析与解决方法
你遇到的System.Net.ProtocolViolationException错误,核心原因是GET请求携带了请求体(Body)——HTTP规范中,GET请求通常不包含请求体,.NET的底层HttpWebRequest默认会阻止这种不符合规范的请求,所以抛出了这个错误。
下面分两种场景给出解决方法,优先推荐第一种(符合REST设计规范):
方案1:改用POST请求(推荐)
登录操作属于提交数据的行为,用POST请求更符合REST规范,也能从根源避免GET带Body的问题。
修改后的ILogin接口
namespace Dashboard.Sdk { using Dashboard.Common.Modelos; using Refit; using System.Threading.Tasks; public interface ILogin { // 把[Get]改为[Post],同时修正路径(原路径中的#应该是输入错误) [Post("/comGpsGate/api/v.1/test/Tokens")] Task<ApiResponse<AuthSuccessResponse>> GetLogin([Body] Login login); } }
WebForms页面代码(无需大幅修改)
注意:要确保你的ASPX页面指令中添加了Async="true",否则异步操作可能出现线程问题:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" Async="true" %>
后台代码保持原有逻辑即可,同时补充更严谨的请求成功判断:
protected async void btnAcceder_Click(object sender, EventArgs e) { try { var api = RestService.For<ILogin>("https://WebApi.Test"); var login = await api.GetLogin(new Login { UserName = TxtEmail.Text, Password = TxtPassword.Text }); if (login == null || !login.IsSuccessStatusCode) { Response.Redirect("Error.aspx?Err=102"); return; } Session["Usuario"] = login.Content.Token; Response.Redirect("Dashboard.aspx"); } catch (Exception ex) { // 可添加异常日志记录逻辑 Response.Redirect("Error.aspx?Err=103"); } }
方案2:如果必须使用GET请求(不推荐)
如果目标API强制要求用GET传递参数,那么不能用[Body],需要把参数转为URL查询字符串传递:
修改后的ILogin接口(单个参数传递)
namespace Dashboard.Sdk { using Dashboard.Common.Modelos; using Refit; using System.Threading.Tasks; public interface ILogin { [Get("/comGpsGate/api/v.1/test/Tokens")] Task<ApiResponse<AuthSuccessResponse>> GetLogin( [Query] string userName, [Query] string password ); } }
后台调用代码
protected async void btnAcceder_Click(object sender, EventArgs e) { try { var api = RestService.For<ILogin>("https://WebApi.Test"); var login = await api.GetLogin(TxtEmail.Text, TxtPassword.Text); if (login == null || !login.IsSuccessStatusCode) { Response.Redirect("Error.aspx?Err=102"); return; } Session["Usuario"] = login.Content.Token; Response.Redirect("Dashboard.aspx"); } catch (Exception ex) { Response.Redirect("Error.aspx?Err=103"); } }
如果你的Login类有多个属性,也可以用[QueryUri]自动序列化对象为查询字符串:
public interface ILogin { [Get("/comGpsGate/api/v.1/test/Tokens{?*}")] Task<ApiResponse<AuthSuccessResponse>> GetLogin([QueryUri] Login login); }
额外注意事项
- WebForms中使用
async void处理按钮事件是允许的,但建议添加try-catch块捕获异步异常,避免未处理异常导致页面崩溃; - 确保Refit版本与.NET Framework版本兼容(推荐使用Refit v6.x及以上版本,支持.NET Framework 4.6.1+);
- 原接口路径中的
#是无效的URL字符,必须去掉,否则会导致请求路径解析错误。
内容的提问来源于stack exchange,提问作者José Donoso
相关产品推荐
相关产品推荐

