Repository: next.js
Issue: Metadata URL resolution incorrectly appends a trailing slash for files when `output: "export"` and `trailingSlash: true`
Labels: bug

### Link to the code that reproduces this issue

https://github.com/mscottford/metadata-trailing-slash-url-resolution-bug

### To Reproduce

1. `git clone https://github.com/mscottford/metadata-trailing-slash-url-resolution-bug`
2. `cd metadata-trailing-slash-url-resolution-bug`
3. `npm install`
4. `npm run start-static`
5. (In a different terminal window, after the HTTP server is running) `npm run test`

### Current vs. Expected behavior

## Background

When generating a static site with `output: "export"` any route handlers in the form of `./app/feed.xml/route.ts` will result in the creation of a `./out/feed.xml` file. Also, the `./app/not-found.tsx` file generates a `./out/404.html` file. This is true even if `trailingSlash: true` is set. That is expected behavior.

## Issue

When `trailingSlash: true` is set, metadata URLs from the `Metadata` object returned by the `generateMetadata` function will have a trailing slash appended, even if the URL references one of the files described above.

### Alternate URLs

Given this metadata function defined in `./app/layout.tsx`.

```
export async function generateMetadata(): Promise<Metadata> {
  return {
    metadataBase: new URL('https://example.com'),
    alternates: {
      canonical: './',
      types: {
        'application/rss+xml': [
          {
            title: 'Example',
            url: '/feed.xml',
          }
        ],
      },
    }
  }
}
```

It's expected that the generated URL would exactly match `https://example.com/feed.xml`. However, the actual value is `https://example.com/feed.xml/`.

### Canonical URL

Given the above `generatedMetadata` function in `./app/layout.tsx`, and the following `generateMetadata` function defined in `./app/not-found.tsx`:

```
export async function generateMetadata(): Promise<Metadata> {
  return {
    alternates: {
      canonical: `/404.html`,
    },
    openGraph: {
      url: `/404.html`,
    }
  }
}
```

It's expected that the canonical URL for the error page would be set to `https://example.com/404.html`. The actual value is `https://example.com/404.html/`.

### OpenGraph URL

Given the above `generateMetadata` function defined in `./app/layout.tsx` and the above `generateMetadata` function defined in `./app/not-found.tsx`.

It's expected that the "og:url" for the error page would be set to `https://example.com/404.html`. The actual value is `https://example.com/404.html/`.

## Reproducing

The tests in the reproducible example repository implement the expectations that are described above.

## Suggested Solution

The metadata URL resolution should use the same logic that is used by the build when it determines whether or not `feed.xml` or `feed.xml/index.html` should be generated. The [`resolveAbsoluteUrlWithPathname` function](https://github.com/vercel/next.js/blob/9798ae52c575a23625fc2b8d412d257ef85a8384/packages/next/src/lib/metadata/resolvers/resolve-url.ts#L97-L99) may need to be changed to add that same logic.


### Provide environment information

```bash
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.2.0: Wed Nov 15 21:53:18 PST 2023; root:xnu-10002.61.3~2/RELEASE_ARM64_T6000
  Available memory (MB): 65536
  Available CPU cores: 10
Binaries:
  Node: 21.5.0
  npm: 10.2.4
  Yarn: 1.22.21
  pnpm: N/A
Relevant Packages:
  next: 14.2.0-canary.0 // Latest available version is detected (14.2.0-canary.0).
  eslint-config-next: 14.1.2
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.1.3
Next.js Config:
  output: export
```


### Which area(s) are affected? (Select all that apply)

App Router, Metadata (metadata, generateMetadata, next/head), Static HTML Export (output: "export")

### Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local)

### Additional context

My deployment target, for the project where I discovered this issue, is an S3 bucket.