diff --git a/scrapy/downloadermiddlewares/redirect.py b/scrapy/downloadermiddlewares/redirect.py
index 26677e527..30cae3fee 100644
--- a/scrapy/downloadermiddlewares/redirect.py
+++ b/scrapy/downloadermiddlewares/redirect.py
@@ -64,7 +64,7 @@ class RedirectMiddleware(BaseRedirectMiddleware):
                 request.meta.get('handle_httpstatus_all', False)):
             return response
 
-        allowed_status = (301, 302, 303, 307)
+        allowed_status = (301, 302, 303, 307, 308)
         if 'Location' not in response.headers or response.status not in allowed_status:
             return response
 
@@ -72,7 +72,7 @@ class RedirectMiddleware(BaseRedirectMiddleware):
 
         redirected_url = urljoin(request.url, location)
 
-        if response.status in (301, 307) or request.method == 'HEAD':
+        if response.status in (301, 307, 308) or request.method == 'HEAD':
             redirected = request.replace(url=redirected_url)
             return self._redirect(redirected, request, spider, response.status)
 

Redirect 308 missing
I did a check on the RedirectMiddleware and noticed that code 308 is missing. Is there a reason for that?
Some websites don't update their sitemap and have a long list of 308 from http to https.

(side note: is there a way to add "s" before a link is scraped?)
diff --git a/tests/test_downloadermiddleware_httpcache.py b/tests/test_downloadermiddleware_httpcache.py
index 12b69860a..22946b98c 100644
--- a/tests/test_downloadermiddleware_httpcache.py
+++ b/tests/test_downloadermiddleware_httpcache.py
@@ -322,6 +322,7 @@ class RFC2616PolicyTest(DefaultStorageTest):
             (True, 203, {'Last-Modified': self.yesterday}),
             (True, 300, {'Last-Modified': self.yesterday}),
             (True, 301, {'Last-Modified': self.yesterday}),
+            (True, 308, {'Last-Modified': self.yesterday}),
             (True, 401, {'Last-Modified': self.yesterday}),
             (True, 404, {'Cache-Control': 'public, max-age=600'}),
             (True, 302, {'Expires': self.tomorrow}),
diff --git a/tests/test_downloadermiddleware_redirect.py b/tests/test_downloadermiddleware_redirect.py
index e8c92affa..35e474418 100644
--- a/tests/test_downloadermiddleware_redirect.py
+++ b/tests/test_downloadermiddleware_redirect.py
@@ -22,12 +22,12 @@ class RedirectMiddlewareTest(unittest.TestCase):
         req2 = self.mw.process_response(req, rsp, self.spider)
         assert req2.priority > req.priority
 
-    def test_redirect_301(self):
-        def _test(method):
-            url = 'http://www.example.com/301'
+    def test_redirect_3xx_permanent(self):
+        def _test(method, status=301):
+            url = 'http://www.example.com/{}'.format(status)
             url2 = 'http://www.example.com/redirected'
             req = Request(url, method=method)
-            rsp = Response(url, headers={'Location': url2}, status=301)
+            rsp = Response(url, headers={'Location': url2}, status=status)
 
             req2 = self.mw.process_response(req, rsp, self.spider)
             assert isinstance(req2, Request)
@@ -42,6 +42,14 @@ class RedirectMiddlewareTest(unittest.TestCase):
         _test('POST')
         _test('HEAD')
 
+        _test('GET', status=307)
+        _test('POST', status=307)
+        _test('HEAD', status=307)
+
+        _test('GET', status=308)
+        _test('POST', status=308)
+        _test('HEAD', status=308)
+
     def test_dont_redirect(self):
         url = 'http://www.example.com/301'
         url2 = 'http://www.example.com/redirected'

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio pytest
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==25.3.0
Automat==24.8.1
cffi==1.17.1
constantly==23.10.4
coverage==7.8.0
cryptography==44.0.2
cssselect==1.3.0
exceptiongroup==1.2.2
execnet==2.1.1
hyperlink==21.0.0
idna==3.10
incremental==24.7.2
iniconfig==2.1.0
jmespath==1.0.1
lxml==5.3.1
packaging==24.2
parsel==1.10.0
pluggy==1.5.0
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
PyDispatcher==2.0.7
pyOpenSSL==25.0.0
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-cov==6.0.0
pytest-mock==3.14.0
pytest-xdist==3.6.1
queuelib==1.7.0
-e git+https://github.com/scrapy/scrapy.git@17bbd71433d3cc3de78b1baf39c36751c1e6fef5#egg=Scrapy
service-identity==24.2.0
six==1.17.0
tomli==2.2.1
Twisted==24.11.0
typing_extensions==4.13.0
w3lib==2.3.1
zope.interface==7.2

name: scrapy
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==25.3.0
      - automat==24.8.1
      - cffi==1.17.1
      - constantly==23.10.4
      - coverage==7.8.0
      - cryptography==44.0.2
      - cssselect==1.3.0
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - hyperlink==21.0.0
      - idna==3.10
      - incremental==24.7.2
      - iniconfig==2.1.0
      - jmespath==1.0.1
      - lxml==5.3.1
      - packaging==24.2
      - parsel==1.10.0
      - pluggy==1.5.0
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pycparser==2.22
      - pydispatcher==2.0.7
      - pyopenssl==25.0.0
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - pytest-xdist==3.6.1
      - queuelib==1.7.0
      - service-identity==24.2.0
      - six==1.17.0
      - tomli==2.2.1
      - twisted==24.11.0
      - typing-extensions==4.13.0
      - w3lib==2.3.1
      - zope-interface==7.2
prefix: /opt/conda/envs/scrapy

tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_redirect_3xx_permanent
tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_dont_redirect tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_latin1_location tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_max_redirect_times tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_priority_adjust tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_redirect_302 tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_redirect_302_head tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_redirect_urls tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_request_meta_handling tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_spider_handling tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_ttl tests/test_downloadermiddleware_redirect.py::RedirectMiddlewareTest::test_utf8_location tests/test_downloadermiddleware_redirect.py::MetaRefreshMiddlewareTest::test_max_redirect_times tests/test_downloadermiddleware_redirect.py::MetaRefreshMiddlewareTest::test_meta_refresh tests/test_downloadermiddleware_redirect.py::MetaRefreshMiddlewareTest::test_meta_refresh_trough_posted_request tests/test_downloadermiddleware_redirect.py::MetaRefreshMiddlewareTest::test_meta_refresh_with_high_interval tests/test_downloadermiddleware_redirect.py::MetaRefreshMiddlewareTest::test_priority_adjust tests/test_downloadermiddleware_redirect.py::MetaRefreshMiddlewareTest::test_redirect_urls tests/test_downloadermiddleware_redirect.py::MetaRefreshMiddlewareTest::test_ttl
scrapy/downloadermiddlewares/redirect.py
scrapy/downloadermiddlewares/redirect.py