question

melonNG-6986 avatar image
0 Votes"
melonNG-6986 asked melonNG-6986 commented

Problem of StatusCode cannot be set.

There are some troublesome crawlers that I want to make a middleware to counter them.

One of them always accesses some page that does not exist. I marked it by the status code and access times.

I got the status code by the code below:

public async Task Invoke(HttpContext context)
{
await _next.Invoke(context);
var statuscode=context.Response.StatusCode;
}

I don't why but if I place the var statuscode=context.Response.StatusCode; before the await _next.Invoke(context);, it always gets 200 status code no matter the page is exist.

If I place it after the await _next.Invoke(context);, it will get the right code. That's why I place it after the await _next.Invoke(context);.

Furthermore, the site will redirect to a reCAPTCHA validation page when the middleware detects the Ip maybe it is a crawler.

So, I modified the code as below:

public async Task Invoke(HttpContext context)
{
await _next.Invoke(context);
var statuscode=context.Response.StatusCode;
Boolean IsCrawler=false;
///some logic to detect the crawler
if(IsCrawler)
{
context.Response.StatusCode = 302;
context.Response.Headers["Cache-Control"] = "no-cache, no-store";
context.Response.Headers["Pragma"] = "no-cache";
context.Response.Headers["Expires"] = "-1";
context.Response.Redirect("");//URL of the reCAPTCHA validation page
return;
}
}

When the codes above are running locally, it won't report any exception.

However, after running on the sever computer, it always reports this error:
StatusCode cannot be set because the response has already started.


Why does the site response before the middleware is running completely? And how can I change the statuscode&header without the exception "StatusCode cannot be set because the response has already started."?

Thank you.

dotnet-aspnet-core-generaldotnet-aspnet-core-mvc
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered melonNG-6986 commented

testing after other middleware leads to issues. the middleware (as in your case) may have already sent the responser headers back to the client. in your case you want to test for crawler and redirect or run more pipeline you code should be:


 public async Task Invoke(HttpContext context)
 {
     Boolean IsCrawler=false;
     ///some logic to detect the crawler
     if(IsCrawler)
     {
         return redirect instead of processing
         context.Response.StatusCode = 302;
         context.Response.Headers["Cache-Control"] = "no-cache, no-store";
         context.Response.Headers["Pragma"] = "no-cache";
         context.Response.Headers["Expires"] = "-1";
         context.Response.Redirect("");//URL of the reCAPTCHA validation page
         return;
     }
    // not crawler - run rest of middleware
    await _next.Invoke(context);
 }
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you. However, you placed the await _next.Invoke(context); after logic of detecting the crawler, it cannot get the correct statuscode.

0 Votes 0 ·

If you place the logic after the invoke, then the response may already written. To handle, you middle ware will need to buffer the response stream, and then decide to out put the buffered response or a new response.

See this thread

https://stackoverflow.com/questions/62588709/re-writing-response-body-asp-net-core-custome-middleware

0 Votes 0 ·

Thank you so much

0 Votes 0 ·