Mic*_*ltu 12 iis azure azure-web-sites asp.net-core-mvc asp.net-core
我有一个在Azure中运行的ASP.NET 6 MVC应用程序.我有一个像这样的动作的控制器
[HttpDelete]
[Route("{image_url}")]
public async Task<IActionResult> RemoveImageUrl([FromRoute(Name = "image_url")] String imageUrlString)
Run Code Online (Sandbox Code Playgroud)
然后我称之为
api/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Full-Size.png"
Run Code Online (Sandbox Code Playgroud)
使用Kestrel进行自托管时,此应用程序正常工作,但是一旦部署到Azure,我就会收到500个错误.我已尽可能多地调试,经过大量的谷歌搜索和戳戳后,似乎IIS正在尝试帮助URL解码请求,然后将其转发给ASP.NET来处理.当然,问题是即使我可以说服IIS接受请求
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
</system.webServer>
<system.web>
<httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters="" relaxedUrlToFileSystemMapping="true"/>
<pages validateRequest="false" />
</system.web>
Run Code Online (Sandbox Code Playgroud)
它仍然解码URL并将解码后的URL传递给ASP.NET,后者找不到匹配的路由.
我该怎么做才能告诉IIS停止尝试在这里提供帮助,只是传递它获得的任何URL,而不进行任何类型的预验证或重写?注意:这是一个Azure Web App,因此我无法直接访问IIS设置.
您只需更新路线定义,使其与解码的图像 url 参数匹配即可。
根据文档,定义路由模板时:
您可以使用 * 字符作为路由值名称的前缀来绑定到 URI 的其余部分。例如,blog/{*slug} 将匹配以 /blog/ 开头且其后具有任何值(将分配给 slug 路由值)的任何 URI。
因此,您可以创建一个与路线匹配的操作[Route("{*image_url}")]:
[Route("{*image_url}")]
public IActionResult RemoveImageUrl([FromRoute(Name = "image_url")]String imageUrlString)
{
return Json(new { ReceivedImage = imageUrlString });
}
Run Code Online (Sandbox Code Playgroud)
我看到的唯一问题是协议部分被解码为http:/单个/. 您有几个选择:
您可以在控制器中手动修复它。更好的是,您可以创建一个模型绑定器和参数约定来自动执行此操作:
[HttpDelete]
[Route("{*image_url}")]
public IActionResult RemoveImageUrl([FullUrlFromEncodedRouteParam(Name = "image_url")] String imageUrlString)
{
return Json(new { ReceivedImage = imageUrlString });
}
public class FullUrlFromUrlEncodedPathSegmentModelBinder : IModelBinder
{
//Matches a url that starts with protocol string and is followed by exactly ":/" instead of "://"
private static Regex incorrectProtocolRegex = new Regex(@"^([a-z][\w-]+:)\/{1}(?!\/)");
//A url path included as a url encoded path segment like http://localhost:39216/image2/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Web.png
//will be decoded by IIS as https:/repocreator.zoltu.io/images/Zoltu-Logo-Web.png, note the single '/' after the protocol
//This model binder will fix it replacing "http:/" with "http://"
public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ValueProvider.GetValue(bindingContext.ModelName) == null)
return Task.FromResult(ModelBindingResult.NoResult);
var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue as string;
var fixedVal = incorrectProtocolRegex.Replace(val, @"$1//");
return Task.FromResult(ModelBindingResult.Success(bindingContext.ModelName, fixedVal));
}
}
public class FullUrlFromEncodedRouteParamAttribute : Attribute, IParameterModelConvention
{
public string Name { get; set; }
public void Apply(ParameterModel parameter)
{
parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
parameter.BindingInfo.BinderModelName = Name;
parameter.BindingInfo.BindingSource = BindingSource.Path;
parameter.BindingInfo.BinderType = typeof(FullUrlFromUrlEncodedPathSegmentModelBinder);
}
}
Run Code Online (Sandbox Code Playgroud)更好的方法可能是更新您的 api,这样您甚至不使用图像密钥中的协议部分。当您需要渲染完整图像 url 时,这将允许您将正确的协议添加到完整图像 url,具体取决于它是否需要 http 还是 https(甚至可以从 url 中省略主机)。您甚至不需要担心客户端对图像路径进行 url 编码,您只需像http://localhost:39216/api/repocreator.zoltu.io/images/Zoltu-Logo-Full-Size.png.
恕我直言,我更喜欢第二种方法。如果您确实需要在路由中编码完整的 url,那么至少您有一种在控制器外部以干净的方式实现它的方法。
注意:如果你想在图片url中保留协议部分,看起来静态文件中间件不喜欢它们,所以必须在Startup.configure中的MVC之后添加它,否则会抛出错误。
| 归档时间: |
|
| 查看次数: |
1490 次 |
| 最近记录: |