6
6
666Wolf6662017-01-20 18:13:11
htaccess
666Wolf666, 2017-01-20 18:13:11

301 redirect with slash to without does not work, how to solve?

The essence of the problem is the following. I set up 301 redirects and compression on the site. I use everything as usual on other sites, but now I'm faced with the fact that .htaccess does not respond to a condition associated with a slash or without.
Tried every option I found online. (for example: web-optimizator.com/301-redirekt-htaccess/).
Everything works, but there is no reaction to the slash ....
Here is my htaccess

Options +FollowSymLinks
RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

# 301 редирект со страниц со слешем на без слеша
RewriteCond %{REQUEST_URI} !\?
RewriteCond %{REQUEST_URI} !\&
RewriteCond %{REQUEST_URI} !\=
RewriteCond %{REQUEST_URI} !\.
RewriteCond %{REQUEST_URI} ![^\/]$
RewriteRule ^(.*)\/$ /$1 [R=301,L]

# Редирект c www на без www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]


# Http to https
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]



# gzip
<IfModule mod_deflate.c>
  # Compress HTML, CSS, JavaScript, Text, XML and fonts
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
  AddOutputFilterByType DEFLATE application/x-font
  AddOutputFilterByType DEFLATE application/x-font-opentype
  AddOutputFilterByType DEFLATE application/x-font-otf
  AddOutputFilterByType DEFLATE application/x-font-truetype
  AddOutputFilterByType DEFLATE application/x-font-ttf
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE font/opentype
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml

  # Remove browser bugs (only needed for really old browsers)
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  # Header append Vary User-Agent
</IfModule>


<IfModule mod_headers.c>
  #кэшировать html и htm файлы на один день
  <FilesMatch "\.(html|htm)$">
    Header set Cache-Control "max-age=43200"
  </FilesMatch>
  #кэшировать css, javascript и текстовые файлы на одну неделю
  <FilesMatch "\.(js|css|txt)$">
    Header set Cache-Control "max-age=604800"
  </FilesMatch>
  #кэшировать флэш и изображения на месяц
  <FilesMatch "\.(flv|swf|ico|gif|jpg|jpeg|png)$">
    Header set Cache-Control "max-age=2592000"
  </FilesMatch>
  #отключить кэширование
  <FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
    Header unset Cache-Control
  </FilesMatch>
</IfModule>


#<IfModule mod_expires.c>
#	ExpiresActive On
#	# Set default expires to 2 days
#	ExpiresDefault A172800
#	ExpiresByType text/css A31536000
#	ExpiresByType application/x-javascript A31536000
#	ExpiresByType text/x-component A31536000
#	ExpiresByType text/html A3600
#	ExpiresByType text/richtext A3600
#	ExpiresByType image/svg+xml A3600
#	ExpiresByType text/plain A3600
#	ExpiresByType text/xsd A3600
#	ExpiresByType text/xsl A3600
#	ExpiresByType text/xml A3600
#	ExpiresByType video/asf A31536000
#	ExpiresByType video/avi A31536000
#	ExpiresByType image/bmp A31536000
#	ExpiresByType application/java A31536000
#	ExpiresByType video/divx A31536000
#	ExpiresByType application/msword A31536000
#	ExpiresByType application/vnd.ms-fontobject A31536000
#	ExpiresByType application/x-msdownload A31536000
#	ExpiresByType image/gif A31536000
#	ExpiresByType application/x-gzip A31536000
#	ExpiresByType image/x-icon A31536000
#	ExpiresByType image/jpeg A31536000
#	ExpiresByType application/vnd.ms-access A31536000
#	ExpiresByType audio/midi A31536000
#	ExpiresByType video/quicktime A31536000
#	ExpiresByType audio/mpeg A31536000
#	ExpiresByType video/mp4 A31536000
#	ExpiresByType video/mpeg A31536000
#	ExpiresByType application/vnd.ms-project A31536000
#	ExpiresByType application/x-font-otf A31536000
#	ExpiresByType application/vnd.oasis.opendocument.database A31536000
#	ExpiresByType application/vnd.oasis.opendocument.chart A31536000
#	ExpiresByType application/vnd.oasis.opendocument.formula A31536000
#	ExpiresByType application/vnd.oasis.opendocument.graphics A31536000
#	ExpiresByType application/vnd.oasis.opendocument.presentation A31536000
#	ExpiresByType application/vnd.oasis.opendocument.spreadsheet A31536000
#	ExpiresByType application/vnd.oasis.opendocument.text A31536000
#	ExpiresByType audio/ogg A31536000
#	ExpiresByType application/pdf A31536000
#	ExpiresByType image/png A31536000
#	ExpiresByType application/vnd.ms-powerpoint A31536000
#	ExpiresByType audio/x-realaudio A31536000
#	ExpiresByType image/svg+xml A31536000
#	ExpiresByType application/x-shockwave-flash A31536000
#	ExpiresByType application/x-tar A31536000
#	ExpiresByType image/tiff A31536000
#	ExpiresByType application/x-font-ttf A31536000
#	ExpiresByType audio/wav A31536000
#	ExpiresByType audio/wma A31536000
#	ExpiresByType application/vnd.ms-write A31536000
#	ExpiresByType application/vnd.ms-excel A31536000
#	ExpiresByType application/zip A31536000
#</IfModule>

Answer the question

In order to leave comments, you need to log in

5 answer(s)
V
Vitaliy Orlov, 2017-01-20
@orlov0562

In my opinion, something strange is written here

# 301 редирект со страниц со слешем на без слеша
RewriteCond %{REQUEST_URI} !\?
RewriteCond %{REQUEST_URI} !\&
RewriteCond %{REQUEST_URI} !\=
RewriteCond %{REQUEST_URI} !\.
RewriteCond %{REQUEST_URI} ![^\/]$
RewriteRule ^(.*)\/$ /$1 [R=301,L]

try replacing with just
# если адрес вида: "/что-угодно-там-дальше..." 
RewriteCond %{REQUEST_URI} ^/.+

# и если адрес попадает под маску: ".../что-угодно-там/"
# делаем редирект на адрес без слеша
RewriteRule ^(.*)\/$ /$1 [R=301,L]

A
Andrey Abramov, 2018-02-04
@zmoe

I also had a problem, it turned out that the caching plugin interfered with the redirect - I changed the plugin and the problem was solved.

A
Alexander Kosarev, 2017-07-28
@jaxtr

In practice, I use the following approach: for each stored entity that the user can create / change, I create a class that describes the form (sometimes it happens that even different classes are used for editing and creating in view of a different set of fields).
This is done for two reasons: firstly, not all fields in the stored entity can be created/modified by users (for example, creation/editing dates and identifiers), and secondly, the removal of validation annotations from the entity class.
Now more to the point: for validation, there are annotations from the javax.validation.constraints package, as well as additional ones provided by Bean Validation API implementations (for example, @Email from Hibernate Validator).
Let's say we have a class that represents a registration form:

SignUpForm.java
public class SignUpForm {
    @Email
    private String email;

    @Size(min = 8)
    @Pattern(regexp = "какая-нибудь регулярка для проверки надёжности пароля")
    private String password;
}

In the controller, we will accept the form like this:
SignUpController.java
public class SignUpController {
    public ResponseEntity signUp(@RequestBody @Valid SignUpForm form, BindingResult bindingResult) {
    }
}

The form will contain the data submitted by the user, and the bindingResult will contain the validation result, which can be easily checked by calling bindingResult.hasErrors() . I will only note that the argument of the BindingResult class must be immediately after the argument marked with @RequestBody and valid annotations , otherwise validation will not work.
But further - more. Let's say we need to add a password confirmation field and check if it matches the password. In this case, we need to add our own annotation (in this case, on the class) and a validator.
New form class:
SignUpForm.java
@PasswordMatch
public class SignUpForm {
    @Email
    private String email;

    @Size(min = 8)
    @Pattern(regexp = "какая-нибудь регулярка для проверки надёжности пароля")
    private String password;

    private String passwordConfirmation;
}

Annotation:
PasswordMatch.java
@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordMatchValidator.class)
@Documented
public @interface PasswordMatch {

    String message() default "{constraints.passwordmatch}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Documented
    @interface List {

        PasswordMatch[] value();
    }
}

Well, the validator:
PasswordMatchValidator.java
public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, SignUpForm> {

    @Override
    public void initialize(PasswordMatch constraintAnnotation) {
    }

    @Override
    public boolean isValid(SignUpForm value, ConstraintValidatorContext context) {
            return Objects.equals(value.getPassword(), value.getPasswordConfirmation());
    }
}

And another way to validate is with the help of spring validators. Let's say we need to check the existence of the specified email in our database, which fits well into the validation process. In this case, we write a validator:
SignUpFormValidator.java
public class SignUpFormValidator implements Validator {
    public boolean supports(Class<?> type) {
        return SignUpForm.class.isAssignableFrom(type);
    }
    public void validate(Object target, Errors errors) {
        SignUpForm form = (SignUpForm) target;
        // проверяем, что нужно и добавляем ошибки в errors, если они есть
    }
}

Register it in the controller:
SignUpController.java
public class SignupController {
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.addValidators(new SignUpFormValidator());
    }
}

After that, Spring will perform additional validation using this validator.
You can read more about validation in Spring in the official documentation .

E
Eugene Khrustalev, 2017-07-28
@eugenehr

1. Include hibernate-validator
2. In DAO objects, add '@Min', '@NotNull', '@Size',... annotations
3. In controller methods that accept DAO objects as parameters, add '@' annotations Valid'

C
Cr2ed, 2017-07-28
@Cr2ed

I see 2 ways:
1. Include form validating
2. You most likely have a class to describe the request. add the validate method there and call it at the beginning of the controller

public class AuthenticateRequestBody {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(final String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(final String password) {
        this.password = password;
    }

    public void validate() {
        if (StringUtils.isBlank(username)) {
            throw new ValidationException("Username is absent!");
        } else if (StringUtils.isBlank(password)) {
            throw new ValidationException("Password is absent!");
        }
    }
}

@PostMapping("/authenticate")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    void authenticate(@RequestBody final AuthenticateRequestBody request) {
        request.validate();

        authenticationService.authenticate(request.getUsername(), request.getPassword());
    }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question