目的
通過一個簡單的項目,在原來的文章基礎上完善一下常用的幾種WebApi編寫方式以及請求方式,一方面是用于給我一個前端朋友用來學習調用接口,另一方面讓我測試HttpClient的一些效果。
本文示例代碼環境:vs2022、net6
準備
新創建了一個.Net WebAPI程序,安裝組件
<ItemGroup><PackageReference?Include="AutoMapper.Extensions.Microsoft.DependencyInjection"?Version="11.0.0"?/><PackageReference?Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson"?Version="6.0.1"?/><PackageReference?Include="Swashbuckle.AspNetCore"?Version="6.3.1"?/><PackageReference?Include="Swashbuckle.AspNetCore.Newtonsoft"?Version="6.3.1"?/>
</ItemGroup>
ConfigureServices配置NewtonsoftJson以及Automapper和操作數據庫代碼(為了省事,刪除了一些不影響當前效果的代碼)
public?void?ConfigureServices(IServiceCollection?services)
{services.AddControllers().AddNewtonsoftJson();services.AddEndpointsApiExplorer();services.AddSwaggerGen(c?=>{c.SwaggerDoc("v1",?new?OpenApiInfo?{?Title?=?"MyWebApi",?Version?=?"v1"?});});//注入AutoMapperservices.AddAutoMapper(Assembly.GetExecutingAssembly().DefinedTypes.Where(t?=>?typeof(Profile).GetTypeInfo().IsAssignableFrom(t.AsType())).Select(t?=>?t.AsType()).ToArray());
}
注意:在Net core3.0以后,微軟移除了Newtonsoft.Json,而使用了System.Text.Json,所以依賴于Newtonsoft.Json的組件將不可用,需要安裝 Microsoft.AspNetCore.Mvc.NewtonsoftJson 包
因為僅僅作為演示,所以我只是新增一個控制器,里面包含了get、post、put、patch、delete幾種類型的接口。這里先不貼代碼,一點一點看。通過一個用戶的添加、修改、刪除作為一個演示的流程。
記得配置允許跨域請求,要不js請求會因為跨域問題而報錯。詳情看此處
數據來源就是控制器里面的一個靜態變量,格式如下
public?class?UserDto
{public?long?UserId?{?get;?set;?}public?string?Name?{?get;?set;?}public?string?Sex?{?get;?set;?}
}
靜態變量如下
private?static?readonly?List<UserDto>?_userDtoList?=?Enumerable.Range(0,?100).Select(t?=>?new?UserDto{Name?=?"張三"?+?t,Sex?=?"男",UserId?=?6974150586715897857?+?t}).ToList();
后端請求的方法我使用的是HttpClient,并且做成了一個公共類,部分需要用到的如下
public?class?HttpClientHelper:?IHttpHelper
{private?readonly?System.Net.Http.HttpClient?_client;///?<summary>///?構造函數///?</summary>///?<param?name="httpClientFactory"></param>public?HttpClientHelper(IHttpClientFactory?httpClientFactory){_client?=?httpClientFactory.CreateClient();}private?void?VerifyParam(string?url,?string?jwtToken,?IDictionary<string,?string>?headers){_client.DefaultRequestHeaders.Clear();if?(string.IsNullOrWhiteSpace(url)){throw?new?ArgumentNullException("url不能為null");}if?(!string.IsNullOrWhiteSpace(jwtToken)){_client.DefaultRequestHeaders.Add("Authorization",?$"Bearer?{jwtToken}");}if?(headers?.Count?>?0){foreach?(var?(key,?value)?in?headers){_client.DefaultRequestHeaders.Add(key,?value);}}}private?static?async?Task<T>?ConvertResponseResult<T>(HttpResponseMessage?httpResponse){//確保成功完成,不是成功就返回具體錯誤信息httpResponse.EnsureSuccessStatusCode();var?resStr?=?await?httpResponse.Content.ReadAsStringAsync();if?(typeof(T)?==?typeof(string))return?(T)Convert.ChangeType(resStr,?typeof(string));return?JsonConvert.DeserializeObject<T>(resStr);}
}
操作
請求頭傳遞token只是為了演示請求頭傳遞參數的寫法,token為偽值
GET
從web服務檢索數據。傳遞參數的本質是url字符串拼接,Request-Head頭部傳遞,Request-Body中不能傳遞(嚴格點說不建議,因為我使用Apifox等工具可以在body中傳值,swagger會提示 Request with GET/HEAD method cannot have body)
Query格式
編寫用戶id查詢用戶信息接口
[HttpGet("user/details")]
public?UserDto?GetUserDetails(long?userId)
{if?(!_userDtoList.Any(t?=>?t.UserId?==?userId))throw?new?ParameterException("未找到用戶標識");return?_userDtoList.Find(t?=>?t.UserId?==?userId);
}
前端請求
$(function?()?{$.ajax({type:?"get",url:?"http://localhost:5000/api/HttpSample/user/details?userId=6974150586715897857",headers:?{?"Authorization":?"Bearer?123456"?},contentType:?"application/json",success:?function?(data,?status)?{if?(status?==?"success")?{console.log(JSON.stringify(data));}}});var?postdata?=?{?userId:?"6974150586715897857"?};$.ajax({type:?"get",headers:{"Authorization":"Bearer?123456"},url:?"http://localhost:5000/api/HttpSample/user/details",data:?postdata,success:?function?(data,?status)?{?if?(status?==?"success")?{console.log(JSON.stringify(data));}??}});
});
后端請求
var?token?=?"123456";//此處token是偽值
var?result?=?await?_httpHelper.GetAsync<ResultModel<UserDto>>("http://localhost:5000/api/HttpSample/user/details?userId=6974150586715897857",?token);
這里的_httpHelper是注入的IHttpHelper(下面其他的方法一樣),對應的GetAsync為
public?async?Task<T>?GetAsync<T>(string?url,?string?jwtToken?=?"",?IDictionary<string,?string>?headers?=?null)
{VerifyParam(url,?jwtToken,?headers);var?response?=?await?_client.GetAsync(url).ConfigureAwait(false);return?await?ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具請求
url:http://localhost:5000/api/HttpSample/user/details?userId=6974150586715897857
并且再請求頭增加:Authorization,值為Bearer xxxx
返回結果如下

POST
在web服務上創建新的數據項。約定用于向服務端提交數據操作,請求時候參數放在參數FromBody傳遞
Json格式
演示添加用戶操作
請求類
public?class?UserDto
{public?long?UserId?{?get;?set;?}public?string?Name?{?get;?set;?}public?string?Sex?{?get;?set;?}
}
接口代碼示例
[HttpPost("user/add")]
public?bool?Add([FromBody]?UserDto?request)
{if?(_userDtoList.Any(t?=>?t.UserId?==?request.UserId))throw?new?ParameterException("用戶標識已經存在");Console.WriteLine(DateTime.Now?+?"???"?+?HttpContext.Request.Headers["Authorization"].FirstOrDefault());_userDtoList.Add(request);return?true;
}
前端請求
$(function?()?{var?param?=?{?userId:?"8974150586715897867",?name:?"老八",?sex:?"女"?};$.ajax({type:?"post",dataType:?'json',contentType:?"application/json",headers:?{?"Authorization":?"Bearer?123456"?},url:?"http://localhost:5000/api/HttpSample/user/add",data:?JSON.stringify(param),success:?function?(data)?{if?(status?==?"success")?{console.log(JSON.stringify(data));}}});
});
后端請求
var?token?=?"123456";//此處token是偽值
var?url?=?"http://localhost:5000/api/HttpSample/user/add";var?usedto?=?new?UserDto
{UserId?=?123456,Name?=?"李四",Sex?=?"女"
};var?result?=?await?_httpHelper.PostAsync<ResultModel<bool>>(url,?usedto,?token);public?async?Task<T>?PostAsync<T>(string?url,?object?data,?string?jwtToken?=?"",?IDictionary<string,?string>?headers?=?null)
{VerifyParam(url,?jwtToken,?headers);var?jsonData?=?data?is?string???data.ToString()?:?JsonConvert.SerializeObject(data);using?var?content?=?new?StringContent(jsonData????string.Empty,?Encoding.UTF8,?"application/json");var?response?=?await?_client.PostAsync(url,?content).ConfigureAwait(false);return?await?ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具請求
傳遞參數格式為json格式,請求頭部默認添加:"Content-Type", "application/json"

x-www-form-unlencoded格式
更新用戶姓名
[HttpPost("user/updatename")]
public?bool?UpdateName([FromForm]?long?userId,?[FromForm]?string?name)
{var?entity?=?_userDtoList.Find(t?=>?t.UserId?==?userId);if?(entity?is?null)throw?new?ParameterException("用戶標識不存在");entity.Name?=?name;return?true;
}
前端請求
$(function?()?{var?postdata?=?{?userId:?"6974150586715897857",?name:?"趙六"?};$.ajax({type:?"post",headers:?{?"Authorization":?"Bearer?123456"?},url:?"http://localhost:5000/api/HttpSample/user/updatename",data:?postdata,success:?function?(data,?status)?{if?(status?==?"success")?{console.log(JSON.stringify(data));}}});
});
后端請求
var?token?=?"123456";//此處token是偽值
var?url?=?"http://localhost:5000/api/HttpSample/user/updatename";
var?dic?=?new?Dictionary<string,?string>
{{?"userId","6974150586715897857"},{?"name","王五"}
};
var?result?=?await?_httpHelper.PostFormDataAsync<ResultModel<bool>>(url,?dic,?token);public?async?Task<T>?PostFormDataAsync<T>(string?url,?Dictionary<string,?string>?data,?string?jwtToken?=?"",?IDictionary<string,?string>?headers?=?null)
{VerifyParam(url,?jwtToken,?headers);var?httpContent?=?new?FormUrlEncodedContent(data);var?response?=?await?_client.PostAsync(url,?httpContent).ConfigureAwait(false);return?await?ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具請求
選擇post請求,參數在Body,然后選擇x-www-form-unlencoded格式。

Form-data格式
模擬上傳用戶頭像操作
[HttpPost("user/uploadImg")]
public?string?Upload([FromForm]?IFormFile?img,?[FromForm]?long?userId)
{if?(img?is?null)throw?new?ParameterException("用戶頭像不能為null");Console.WriteLine(HttpContext.Request.Headers["Authorization"].FirstOrDefault());var?entity?=?_userDtoList.Find(t?=>?t.UserId?==?userId);if?(entity?is?null)throw?new?ParameterException("用戶標識不存在");return?img.FileName;
}
注意:當你上傳大于30000000字節長度的文件時候,需要修改上傳文件的默認限制
前端請求
$(function?()?{$("#tijiao").click(function?()?{//logoimg是<input?type="file"?id="logoimg""?/>var?files?=?$("#logoimg").prop('files');?//獲取到文件列表var?formData?=?new?FormData();formData.append("userId",?"6974150586715897857");formData.append("img",?files[0],?"1122.jpg");//圖片文件流console.log(formData);$.ajax({type:?'post',url:?"http://localhost:5000/api/HttpSample/user/uploadImg",headers:?{"Authorization":?"Bearer?123456"},mimeType:?"multipart/form-data",processData:?false,contentType:?false,data:?formData,success:?function?(data)?{//后端Httpclient請求成功后返回過來的結果console.log(data);}});});
});
后端請求
var?url?=?"http://localhost:5000/api/HttpSample/user/uploadImg";var?formData?=?new?MultipartFormDataContent();var?bytes?=?System.IO.File.ReadAllBytes("D:\\Downloads\\11111.jpg");
var?byteContent?=?new?ByteArrayContent(bytes);
byteContent.Headers.ContentDisposition?=?new?System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{Name?=?"img",FileName?=?"111.jpg"
};
formData.Add(byteContent);//?寫法一
formData.Add(new?StringContent("6974150586715897857"),?"userId");//?寫法二
var?byteContent2?=?new?ByteArrayContent(Encoding.UTF8.GetBytes("天氣"));
byteContent2.Headers.ContentDisposition?=?new?System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{Name?=?"name",
};
formData.Add(byteContent2);var?headerDic?=?new?Dictionary<string,?string>
{{?"Authorization","Bearer?123456"},
};var?result?=?await?_httpHelper.PostFormDataAsync<ResultModel<string>>(url,?formData,?headerDic);public?async?Task<T>?PostFormDataAsync<T>(string?url,?MultipartFormDataContent?data,?IDictionary<string,?string>?headers?=?null)
{VerifyParam(url,?"",?headers);var?result?=?await?_client.PostAsync(url,?data).ConfigureAwait(false);return?await?ConvertResponseResult<T>(result);
}
接口工具請求
選擇Body=>form-data

PUT
更新web服務上的數據項。
Json格式
更新用戶信息
[HttpPut("user/update")]
public?bool?Update(UserDto?userDto)
{if?(userDto?is?null)throw?new?ParameterException("參數不能為空");Console.WriteLine(DateTime.Now?+?"????"?+?HttpContext.Request.Headers["Authorization"].FirstOrDefault());var?currUser?=?_userDtoList.Find(t?=>?t.UserId?==?userDto.UserId);if?(currUser?is?null)throw?new?ParameterException("用戶標識不存在");currUser.Name?=?userDto.Name;currUser.Sex?=?userDto.Sex;return?true;
}
前端請求
$(function?()?{var?param?=?{?userId:?"6974150586715897859",?name:?"老八",?sex:?"女"?};$.ajax({type:?"put",dataType:?'json',contentType:?"application/json",headers:?{?"Authorization":?"Bearer?123456"?},url:?"http://localhost:5000/api/HttpSample/user/update",data:?JSON.stringify(param),success:?function?(data,?status)?{if?(status?==?"success")?{console.log(JSON.stringify(data));}}});
});
后端請求
var?token?=?"123456";//此處token是偽值var?usedto?=?new?UserDto
{UserId?=?6974150586715897859,Name?=?"老八",Sex?=?"女"
};var?url?=?"http://localhost:5000/api/HttpSample/user/update";var?result?=?await?_httpHelper.PutAsync<ResultModel<bool>>(url,?usedto,?token);
return?JsonConvert.SerializeObject(result);public?async?Task<T>?PutAsync<T>(string?url,?object?data,?string?jwtToken?=?"",?IDictionary<string,?string>?headers?=?null)
{VerifyParam(url,?jwtToken,?headers);var?jsonData?=?data?is?string???data.ToString()?:?JsonConvert.SerializeObject(data);using?var?content?=?new?StringContent(jsonData????string.Empty,?Encoding.UTF8,?"application/json");var?response?=?await?_client.PutAsync(url,?content).ConfigureAwait(false);return?await?ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具請求
URL:http://localhost:5000/api/HttpSample/user/update
參數傳遞:Body=>json

DELETE
刪除web服務上的數據項。
Query格式
刪除用戶信息
[HttpDelete("user")]
public?bool?Delete(long?userId)
{var?entity?=?_userDtoList.Find(t?=>?t.UserId?==?userId);if?(entity?is?null)throw?new?ParameterException("用戶標識不存在");Console.WriteLine(DateTime.Now?+?"????"?+?HttpContext.Request.Headers["Authorization"].FirstOrDefault());_userDtoList.Remove(entity);return?true;
}
前端請求
$(function?()?{$.ajax({type:?"DELETE",url:?"http://localhost:5000/api/HttpSample/user?userId=6974150586715897861",headers:?{?"Authorization":?"Bearer?123456"?},success:?function?(data,?status)?{if?(status?==?"success")?{console.log(JSON.stringify(data));}}});
});
后端請求
var?token?=?"123456";//此處token是偽值
var?url?=?"http://localhost:5000/api/HttpSample/user?userId=6974150586715897862";var?result?=?await?_httpHelper.DeleteAsync<ResultModel<bool>>(url,?token);public?async?Task<T>?DeleteAsync<T>(string?url,?string?jwtToken?=?"",?IDictionary<string,?string>?headers?=?null)
{VerifyParam(url,?jwtToken,?headers);var?response?=?await?_client.DeleteAsync(url).ConfigureAwait(false);return?await?ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具請求
URL:http://localhost:5000/api/HttpSample/user?userId=6974150586715897859

Patch
通過描述有關如何修改項的一組說明,更新web服務上的數據項。
請求格式如下:
[{"op" : "replace", "path" : "/PassWord", "value" : "222222"}]
op屬性指示操作的類型,path屬性指示要更新的元素,value屬性提供新值。
add:添加屬性或數組元素。對于現有屬性:設置值。
remove:刪除屬性或數組元素。
replace:替換操作
為了支持該請求方式,需要安裝nuget包Microsoft.AspNetCore.Mvc.NewtonsoftJson。
參考文檔:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/jsonpatch?view=aspnetcore-6.0
Json格式
在此用于更新數據
[HttpPatch("user/update2/{userId}")]
public?UserDto?Update2([FromRoute]?long?userId,?JsonPatchDocument<UserDto>?jsonPatch,?[FromServices]?IMapper?mapper)
{var?entity?=?_userDtoList.Find(t?=>?t.UserId?==?userId);if?(entity?is?null)throw?new?ParameterException("用戶標識無效");var?dto?=?mapper.Map<UserDto>(entity);jsonPatch.ApplyTo(dto,?ModelState);var?user?=?_userDtoList.Find(t?=>?t.UserId?==?userId);mapper.Map(dto,?user);return?user;
}
前端請求
演示根據用戶id去更新用戶的姓名
$(function?()?{var?par?=?[{?"op":?"replace",?"path":?"/name",?"value":?"老六"?}];$.ajax({type:?"Patch",url:?"http://localhost:5000/api/HttpSample/user/update2/6974150586715897857",headers:?{?"Authorization":?"Bearer?123456"?},contentType:?"application/json",data:?JSON.stringify(par),success:?function?(result)?{console.log(result);}});
});
后端請求
var?token?=?"123456";//此處token是偽值
var?url?=?"http://localhost:5000/api/HttpSample/user/update2/6974150586715897859";
var?content?=?"[{\"op\":\"replace\",\"path\":\"/name\",\"value\":\"小七七\"}]";
var?result?=?await?_httpHelper.PatchAsync<ResultModel<UserDto>>(url,?content,?token);public?async?Task<T>?PatchAsync<T>(string?url,?object?data,?string?jwtToken?=?"",?IDictionary<string,?string>?headers?=?null)
{VerifyParam(url,?jwtToken,?headers);var?jsonData?=?data?is?string???data.ToString()?:?JsonConvert.SerializeObject(data);using?var?content?=?new?StringContent(jsonData????string.Empty,?Encoding.UTF8,?"application/json");var?response?=?await?_client.PatchAsync(url,?content).ConfigureAwait(false);return?await?ConvertResponseResult<T>(response).ConfigureAwait(false);
}
接口工具請求
參數傳遞:Body=>json
