目的
通過一個簡單的項目,在原來的文章基礎上完善一下常用的幾種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" });
});
//注入AutoMapper
services.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