一、异常描述

.Net core相关api接口报错404,找不到对应的接口路径

二、异常分析

DMS根站点配置了Url重写规则,具体规则见图2. url重写规则内容。这里会拦截所有/api开始的接口请求路径,并转发到http://192.168.160.28:5002/路径下,导致不同项目里的接口出现404错误。

图1. 站点url重写规则

图2. url重写规则内容

三、解决方案

1. 定制个性化接口路径

这个方案延续使用了第二节里的配置方案,差别在于将你所需要的接口路径写成特殊格式,例如:/{{项目名称}}/xxxapi/v1这样在更改url重写规则时不会出现拦截其他项目中url。

但是这个方法不是最佳方案,还是改动了整个DMS的配置,建议使用下一种方案。

2. .Net core添加虚拟目录

2.1 配置swagger中间件

startup.cs中添加如下代码,

  1. // 1.生成json文件时,生成到虚拟目录下,VDir 来自配置
  2. app.UseSwagger(c =>
  3. {
  4. if (!string.IsNullOrEmpty(VDir))
  5. {
  6. // 设定模板:by webmote csdn
  7. c.RouteTemplate = $"/{VDir}/swagger/{{documentName}}/swagger.json";
  8. c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
  9. {
  10. //api测试时增加虚拟目录 或完整路径也可以,完整路径已被webmote注释
  11. swaggerDoc.Servers = new List<OpenApiServer> { new OpenApiServer {
  12. Url = $"/{VDir}"
  13. // Url = $"{httpReq.Scheme}://{httpReq.Host.Value}/{virtualPath}"
  14. } };
  15. });
  16. }
  17. });
  18. // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
  19. app.UseSwaggerUI(c =>
  20. {
  21. if (!string.IsNullOrEmpty(VDir))
  22. {
  23. c.SwaggerEndpoint($"/{VDir}/swagger/v1/swagger.json", "App API V1");
  24. c.RoutePrefix = $"{VDir}/swagger";
  25. }
  26. else
  27. {
  28. c.SwaggerEndpoint("/swagger/v1/swagger.json", "App API V1");
  29. }
  30. });
2.2 配置appsettings.json
  1. {
  2. "AppSettings": {
  3. "VirtualPath": "/虚拟目录"
  4. }
  5. }
2.3 对Api增加虚拟目录支持
  1. public class MyTransformer : DynamicRouteValueTransformer
  2. {
  3. private string _route = string.Empty;
  4. public MyTransformer(string route)
  5. {
  6. _route = route;
  7. }
  8. public override ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
  9. {
  10. if (!values.ContainsKey("dir")) return new ValueTask<RouteValueDictionary>(values);
  11. var dir = (string)values["dir"];
  12. return new ValueTask<RouteValueDictionary>(values);
  13. }
  14. }
这里引入了{dir}路由配置,把该类注入到服务中
  1. if (!string.IsNullOrEmpty(VDir))
  2. {
  3. services.AddSingleton<MyTransformer>(new MyTransformer(VDir));
  4. }
UseEndpoints配置时,增加对二级目录的路由解释映射。
  1. app.UseEndpoints(endpoints =>
  2. {
  3. endpoints.MapControllers();
  4. if (!string.IsNullOrEmpty(VirtualPath))
  5. {
  6. //这里是webmote定义的路由映射,可以方便的忽略二级目录
  7. endpoints.MapDynamicControllerRoute<MyTransformer>("{VirtualPath}/api/{controller}/{action}/{id?}");
  8. }
  9. });
控制器WebApi的路由保持不变,不需要增加二级目录的
[Route(“api/[controller]/[action]”)]