Redirect to URL with POST method in Asp.Net Core
Solution 1
EDIT: Ah, just now checked the comments. If the initial request is a GET, then this won't work either and you can't tell the browser to POST. Not without returning a view that auto-executes a form with JavaScript.
You need to return a 308, not a 301.
Here is the changed code:
private static void RedirectToAPI(RewriteContext context)
{
var request = context.HttpContext.Request;
if (request.Path.Value.StartsWith("/apiendpoint", StringComparison.OrdinalIgnoreCase))
{
var json = JsonConvert.SerializeObject(request.Path.Value
.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
.Skip(1));
var response = context.HttpContext.Response;
response.Headers[HeaderNames.Location] = $"/custom";
response.StatusCode = 308;
context.Result = RuleResult.EndResponse;
using (var bodyWriter = new StreamWriter(response.Body))
{
bodyWriter.Write(json);
bodyWriter.Flush();
}
}
}
308 is a permanent redirect that requires the browser to preserve the method. https://httpstatuses.com/308
The temporary version is 307.
Convenience methods for these redirects are available in MVC Core 2.0.0-preview1.
Solution 2
This is a sample code
public class ConvertGetToPostHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Add your logic here to decide if the request Method needs to be changed
// Caution: This works only if you're redirecting internally
request.Method = HttpMethod.Post;
return await base.SendAsync(request, cancellationToken);
}
}
You will have to add the Handler to Handler Pipeline as
config.MessageHandlers.Add(new ConvertGetToPostHandler());
Also, read over this documentation to get some insight into it's purpose and usage.
Solution 3
Can you set @juunas answer as a correct answer, his answer solved it for me as you can see in my example code.
internal class RedirectCultureRule : IRule
{
private const string CultureKey = "culture";
public void ApplyRule(RewriteContext context)
{
HttpRequest httpRequest = context.HttpContext.Request;
httpRequest.Query.TryGetValue(CultureKey, out StringValues cultureValues);
string culture = cultureValues;
if (cultureValues.Count > 0 && culture.IsCultureMatch())
{
context.Result = RuleResult.ContinueRules;
return;
}
Dictionary<string, string> queryParts = new Dictionary<string, string>();
NameValueCollection queryString = HttpUtility.ParseQueryString(httpRequest.QueryString.ToString());
foreach (string key in queryString)
{
queryParts[key.Trim()] = queryString[key].Trim();
}
if (!queryParts.ContainsKey(CultureKey))
{
queryParts[CultureKey] = CultureInfo.CurrentCulture.Name;
}
string query = $"?{string.Join("&", queryParts.Select(qp => $"{qp.Key}={qp.Value}"))}";
if (query.Length > 1)
{
httpRequest.QueryString = new QueryString(query);
}
string url = UriHelper.GetDisplayUrl(httpRequest);
HttpResponse httpResponse = context.HttpContext.Response;
httpResponse.StatusCode = 308;
httpResponse.Headers[HeaderNames.Location] = url;
using (StreamReader requestReader = new StreamReader(httpRequest.Body))
{
using (StreamWriter responseWriter = new StreamWriter(httpResponse.Body))
{
string body = requestReader.ReadToEnd();
responseWriter.Write(body);
responseWriter.Flush();
}
}
context.Result = RuleResult.EndResponse;
}
}
Solution 4
If using ASP.NET Core 2.0 there is RedirectPermanentPreserveMethod, you can read about it here. If this method is not supported you can try doing it manually.
Yurii N.
Updated on June 17, 2022Comments
-
Yurii N. almost 2 years
I have simple url rewriter:
private static void RedirectToAPI(RewriteContext context) { var request = context.HttpContext.Request; if (request.Path.Value.StartsWith("/apiendpoint", StringComparison.OrdinalIgnoreCase)) { var json = JsonConvert.SerializeObject(request.Path.Value .Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries) .Skip(1)); var response = context.HttpContext.Response; response.Headers[HeaderNames.Location] = $"/custom"; response.StatusCode = StatusCodes.Status301MovedPermanently; context.Result = RuleResult.EndResponse; using (var bodyWriter = new StreamWriter(response.Body)) { bodyWriter.Write(json); bodyWriter.Flush(); } } }
The problem is, when it redirects to /custom url, request has method GET, while this method require POST.
For example, send GET request to url /apiendpoint/first/second/third, then rewriter responds to redirect, accordingly, the following request must be with method POST, but now, it is GET.
How can I change method of request, which is after url rewriter response?