2016-05-12 44 views
9

我有一個在Azure中運行的ASP.NET 6 MVC應用程序。我有一個動作控制器像如何在Azure中允許URL編碼路徑段

[HttpDelete] 
[Route("{image_url}")] 
public async Task<IActionResult> RemoveImageUrl([FromRoute(Name = "image_url")] String imageUrlString) 

然後我把它像

api/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Full-Size.png" 

此應用程序正常工作時的自我與Kestrel的託管,但只要我部署到Azure中,我得到500錯誤。我儘可能多地進行了調試,並且經過大量Google搜索後,似乎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> 

請求它仍然解碼URL並傳遞到ASP.NET解碼URL不找到一個匹配的路由。

我該怎麼做才能告訴IIS停止嘗試在此處獲得幫助,並且只傳遞它獲取的任何URL,而不進行任何形式的預驗證或重寫。注意:這是一個Azure Web應用程序,所以我沒有直接訪問IIS設置。

+0

米卡,我遇到了類似的問題......你有沒有想出一個令人滿意的解決方案? – err1100

+0

我最終登陸的解決方案是停止使用IIS進行託管。我不記得我是否解決了這個具體的解決方案,但是總的來說,IIS最終比它更值得痛苦。我現在把我的所有東西都放到了Kestrel的Docker中,我的生活變得更加簡單了。 –

+0

哈。好的謝謝。 – err1100

回答

2

您可以更新您的路由定義,以便它與解碼的圖像url參數相匹配。

the documentation,定義路由模板時:

可以使用*字符作爲前綴的路由值名稱綁定 到URI的其餘部分。例如,博客/ {* slug}將匹配任何以/ blog /開頭並具有任何後續值(將 分配給slug路由值)的URI 。

所以,你可以創建匹配的路由[Route("{*image_url}")]一個動作:

[Route("{*image_url}")] 
public IActionResult RemoveImageUrl([FromRoute(Name = "image_url")]String imageUrlString) 
{ 
    return Json(new { ReceivedImage = imageUrlString }); 
} 

我所看到的唯一的問題是,該協議的一部分解碼爲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);   
        } 
    } 
    
  • 一種更好的方法可能會更新您的API,所以你甚至不使用的圖像鍵協議部分。這將允許您在需要呈現完整圖像url時添加適當的協議,具體取決於它是否需要http或https(即使主機可以從url中刪除)。你甚至不需要擔心你的客戶端的圖像路徑的URL編碼,你可以像http://localhost:39216/api/repocreator.zoltu.io/images/Zoltu-Logo-Full-Size.png那樣調用它。

恕我直言,我寧願第二種方法。如果你真的需要在路由中編碼完整的url,那麼至少你有一種方法可以在控制器之外以乾淨的方式實現它。

注意:如果您想保留協議部分在圖像的URL,它看起來像靜態文件中間件不喜歡他們,所以它具有MVC中Startup.configure後加入,否則會拋出錯誤。

+0

雖然您的建議可以讓我解決即時問題(對前端和後端都做出更改),但它沒有解決根本問題,即如何在Azure * NOT * URL解碼請求之前製作IIS傳遞給我的框架。 IIS的行爲違背了URL規範,我真的想要一種使用URL Encoding的方式來設計它,並且可以通過Web服務器和靈活的方式進行移植(API用戶不必知道IIS)。 –

+0

我同意它不會改變Azure如何對待網址,但用戶不需要知道有關Azure的具體內容是不是? 'http:// localhost:39216/api/repocreator.zoltu.io%2Fimages%2FZoltu-Logo-Full-Size.png'和'http:// localhost:39216/api/repocreator.zoltu.io/images/Zoltu-Logo-Full-Size.png'可以正常工作。 –

+0

除非我誤解了你的建議,如果我的API的用戶用'.../api/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Web.png調用它,因爲IIS會誤解URL Encoded'//'而導致崩潰。這意味着用戶行爲合理將失敗,因爲後端恰好在IIS上運行(並且沒有正確處理URL編碼)。如果後端在Kestrel上運行,請求將會有效。 –