fix: HTTPS URLs in sitemap, robots, canonical + og:image on homepage
- Add UseForwardedHeaders middleware so Request.Scheme = "https" behind nginx - Add SITE_BASE_URL env var fallback for sitemap.xml, robots.txt, and all Razor page canonical/og URLs — set it to https://draletaha.ir in .env - Add og:image to homepage using hero photo - Add SITE_BASE_URL to docker-compose.yml environment block Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
@section Head {
|
||||
<title>@ViewData["Title"]</title>
|
||||
<meta name="description" content="مقالات تخصصی دکتر سوسن آلطه درباره زیبایی پوست، بوتاکس، فیلر، لیزر و مراقبت از پوست." />
|
||||
<link rel="canonical" href="@(Request.Scheme + "://" + Request.Host + "/blog")" />
|
||||
<link rel="canonical" href="@((Environment.GetEnvironmentVariable("SITE_BASE_URL")?.TrimEnd('/') ?? (Request.Scheme + "://" + Request.Host)) + "/blog")" />
|
||||
<style>
|
||||
/* ─── Blog Hero ─────────────────────────────────────────────── */
|
||||
.blog-hero{background:linear-gradient(135deg,var(--gold-pale) 0%,#EDE0CA 100%);padding:6rem 2rem 3rem;text-align:center}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@model DrSousan.Api.Pages.Blog.PostModel
|
||||
@{
|
||||
var post = Model.Post!;
|
||||
var baseUrl = Request.Scheme + "://" + Request.Host;
|
||||
var baseUrl = Environment.GetEnvironmentVariable("SITE_BASE_URL")?.TrimEnd('/') ?? (Request.Scheme + "://" + Request.Host);
|
||||
var canonicalUrl = baseUrl + "/blog/" + post.Slug;
|
||||
var ogImage = ViewData["OgImage"]?.ToString() ?? "";
|
||||
var articleType = ViewData["ArticleType"]?.ToString() ?? "MedicalWebPage";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@page
|
||||
@model IndexModel
|
||||
@{
|
||||
var siteBaseUrl = Environment.GetEnvironmentVariable("SITE_BASE_URL")?.TrimEnd('/') ?? (siteBaseUrl);
|
||||
var h = Model.Hero;
|
||||
var a = Model.About;
|
||||
var c = Model.Contact;
|
||||
@@ -24,14 +25,21 @@
|
||||
<meta property="og:title" content="@ViewData["Title"]" />
|
||||
<meta property="og:description" content="@h.GetValueOrDefault("subtitle","")" />
|
||||
<meta property="og:locale" content="fa_IR" />
|
||||
<link rel="canonical" href="@(Request.Scheme + "://" + Request.Host + "/")" />
|
||||
@if (!string.IsNullOrEmpty(heroImg))
|
||||
{
|
||||
var absHeroImg = heroImg.StartsWith("http") ? heroImg : (siteBaseUrl + heroImg);
|
||||
<meta property="og:image" content="@absHeroImg" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
}
|
||||
<link rel="canonical" href="@(siteBaseUrl + "/")" />
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context":"https://schema.org",
|
||||
"@@type":["MedicalBusiness","LocalBusiness"],
|
||||
"name":"@siteName",
|
||||
"description":"@h.GetValueOrDefault("subtitle","")",
|
||||
"url":"@(Request.Scheme + "://" + Request.Host)",
|
||||
"url":"@(siteBaseUrl)",
|
||||
"telephone":"@c.GetValueOrDefault("phone","")",
|
||||
"address":{"@@type":"PostalAddress","addressLocality":"تهران","addressCountry":"IR","streetAddress":"@c.GetValueOrDefault("address","")"},
|
||||
"openingHours":"@c.GetValueOrDefault("hours","")",
|
||||
|
||||
+14
-2
@@ -56,6 +56,15 @@ builder.Services.ConfigureHttpJsonOptions(opts =>
|
||||
|
||||
// ── Build ─────────────────────────────────────────────────────────────────────
|
||||
var app = builder.Build();
|
||||
|
||||
// Trust the X-Forwarded-Proto header from nginx so ctx.Request.Scheme = "https"
|
||||
// This fixes canonical URLs, sitemap, robots.txt, og:image all using http:// on production
|
||||
app.UseForwardedHeaders(new Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersOptions
|
||||
{
|
||||
ForwardedHeaders = Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedFor
|
||||
| Microsoft.AspNetCore.HttpOverrides.ForwardedHeaders.XForwardedProto
|
||||
});
|
||||
|
||||
app.UseCors();
|
||||
app.UseDefaultFiles(); // serves /admin/index.html for /admin/ (wwwroot/index.html deleted → no conflict with Razor Pages)
|
||||
app.UseStaticFiles();
|
||||
@@ -780,7 +789,9 @@ app.MapDelete("/api/health-requests/{id:int}", async (int id, AppDbContext db) =
|
||||
// ── Sitemap ───────────────────────────────────────────────────────────────────
|
||||
app.MapGet("/sitemap.xml", async (AppDbContext db, HttpContext ctx) =>
|
||||
{
|
||||
var baseUrl = $"{ctx.Request.Scheme}://{ctx.Request.Host}";
|
||||
// SITE_BASE_URL env var wins (e.g. "https://draletaha.ir") — falls back to request scheme+host
|
||||
var baseUrl = Environment.GetEnvironmentVariable("SITE_BASE_URL")?.TrimEnd('/')
|
||||
?? $"{ctx.Request.Scheme}://{ctx.Request.Host}";
|
||||
var published = await db.BlogPosts.Where(p => p.IsPublished)
|
||||
.Select(p => new { p.Slug, p.UpdatedAt }).ToListAsync();
|
||||
|
||||
@@ -814,7 +825,8 @@ app.MapGet("/healthz", () => Results.Ok(new { status = "healthy", utc = DateTime
|
||||
// ── Robots.txt ────────────────────────────────────────────────────────────────
|
||||
app.MapGet("/robots.txt", (HttpContext ctx) =>
|
||||
{
|
||||
var host = $"{ctx.Request.Scheme}://{ctx.Request.Host}";
|
||||
var host = Environment.GetEnvironmentVariable("SITE_BASE_URL")?.TrimEnd('/')
|
||||
?? $"{ctx.Request.Scheme}://{ctx.Request.Host}";
|
||||
var body = $"User-agent: *\nAllow: /\nDisallow: /admin/\nDisallow: /api/\n\nSitemap: {host}/sitemap.xml";
|
||||
ctx.Response.ContentType = "text/plain";
|
||||
return ctx.Response.WriteAsync(body);
|
||||
|
||||
@@ -23,6 +23,7 @@ services:
|
||||
Admin__Username: "${ADMIN_USERNAME:-admin}"
|
||||
Admin__Password: "${ADMIN_PASSWORD:-admin123}"
|
||||
ASPNETCORE_ENVIRONMENT: "Production"
|
||||
SITE_BASE_URL: "${SITE_BASE_URL:-}"
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
||||
Reference in New Issue
Block a user