MrMo Program Learning


  • 首页

  • Java

  • 设计模式

IE6-IE11 Get请求参数带中文tomcat 返回400错误并显示:Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986

发表于 2017-11-19 | 分类于 Java

Tomcat出现版本

  • 7.0.69+
  • 8.0.39+
  • 8.5.7+

原因

  • IE6-IE11(Edge 不存在,可能修改了编码方案) 中文会被IE使用iso-8859-1编码 编码后的中文字符串带\,这是RFC文档中规定的不安全字符,Tomcat在高版本中增加的安全验证,凡是RFC 3986中非URL可携带的字符,都会返回400错误

解决方案

  • 前端对中文URLEncoding后在发送请求,后端要么修改tomcat源码要么降低tomcat版本,否则无法解决这个bug,查阅资料后并没有找到可以更改IE默认编码的方法,后端在tomcat的server.xml中增加urlencoding配置也无法解决这个问题,因为这个问题根本都还没有进入到业务层就已经被拦截返回了。所以,综上,前端转码是最好的方案,因为Url参数中带中文本来就是不符合规范的。

附 RFC 3986文档关于特殊字符的定义

  • RFC3986文档规定,Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符。

  • RFC3986中指定了以下字符为保留字符:
    ! * ‘ ( ) ; : @ & = + $ , / ? # [ ]

  • 以下为不安全字符

    • 空格 Url在传输的过程,或者用户在排版的过程,或者文本处理程序在处理Url的过程,都有可能引入无关紧要的空格,或者将那些有意义的空格给去掉
    • 引号以及<> 引号和尖括号通常用于在普通文本中起到分隔Url的作用
    • #通常用于表示书签或者锚点
    • % 百分号本身用作对不安全字符进行编码时使用的特殊字符,因此本身需要编码
    • {}|\^[]`~ 某一些网关或者传输代理会篡改这些字符

观察者(Observer)模式

发表于 2017-11-18 | 分类于 设计模式

定义

观察者模式定义了一系列对象之间的一对多的关系,当一个对象改变状态,其他依赖者都会收到通知

简单实现

  • Subject.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface Subject {

    public void registerObserver(Observer o);

    public void removeObserver(Observer o);

    public void notifyObservers(Object changeData);

    }
  • Observer.java

    1
    2
    3
    4
    5
    public interface Observer {

    public void update(Object ChangeData);

    }
  • ConcreteSubject.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class ConcreteSubject implements Subject {

    private List<Observer> observers = new ArrayList<>();

    @Override
    public void registerObserver(Observer o) {
    observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
    int index = observers.indexOf(o);
    if (index > 0){
    observers.remove(o);
    }
    }

    @Override
    public void notifyObservers(Object changeData) {
    for (Observer o : observers){
    o.update(changeData);
    }
    }

    public void change(Object changeData){
    notifyObservers(changeData);
    }
    }
  • ConcreteObserver.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class ConcreteObserver implements Observer {

    private String name;

    public ConcreteObserver(String name){
    this.name = name;
    }

    @Override
    public void update(Object ChangeData) {
    System.out.println("Subject has new data to me " + name +" ChangeData" +ChangeData);
    }
    }
  • 在观察者模式中,每个Subject都会持有观察者的引用,通过调用registerObserver()方法进行注册,通过removeObserver()移除,一旦Subject发生change(),就会通知所有注册的Observer,这样就起到了一个通知的作用,这样会有个不好的影响就是,有可能主题可能更新了许多内容,并且会将这些内容全部下发给Observer,但是并不是每个Observer都需要这些全部的数据,所以这个时候就可以考虑在Subject中增加一些getter,让Observer自己来取数据,Subject只需要通知Observer有新的数据,Observer根据自己的业务来获取数据,但是这样做也有不好的地方,Subject需要暴露更多的内容给Observer,Observer必须知道Subject的业务接口才能获取自己需要的东西,这就导致耦合度增加了。

Java内置的观察者模式

  • Observable.java
  • Observer.java
1
2
3
4
5
6
7
8
9
10
public class JavaSubject extends Observable {


public void change(Object changeData){
setChanged();
notifyObservers(changeData);
}


}
1
2
3
4
5
6
7
public class JavaObserver implements Observer {

@Override
public void update(Observable o, Object arg) {
System.out.println(o + "has new Data" + arg);
}
}
  • Java 内置了观察者模式的方法,通过继承Observable和实现Observer,就能实现这个设计模式,不过Java内置的Observable,并不是一个接口,这就意味着必须要继承这个父类,然而实际情况中,如果Observer需要继承其他类时,这就很难做出抉择,而且Observable的setchanged()方法是protect的,那就意味着只有Observable的子类才能使用,除非你是Observable的子类,否则你将无法创建Observable实例,并把它组合到自己的类中来。这就违反了设计模式中的少用继承,多用组合的原则。不过,无论怎样,在了解这个模式以后,会知道在什么时候去用什么样的实现。

MrMo

2 日志
2 分类
© 2017 MrMo
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.2